diff options
Diffstat (limited to 'drivers/staging/comedi')
240 files changed, 55646 insertions, 106631 deletions
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 1502d80f6f7..a2f6957e7ee 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -1,22 +1,38 @@ config COMEDI tristate "Data acquisition support (comedi)" - default N depends on m ---help--- Enable support a wide range of data acquisition devices for Linux. +if COMEDI + config COMEDI_DEBUG bool "Comedi debugging" - depends on COMEDI != n ---help--- This is an option for use by developers; most people should say N here. This enables comedi core and driver debugging. +config COMEDI_DEFAULT_BUF_SIZE_KB + int "Comedi default initial asynchronous buffer size in KiB" + default "2048" + ---help--- + This is the default asynchronous buffer size which is used for + commands running in the background in kernel space. This + defaults to 2048 KiB of memory so that a 16 channel card + running at 10 kHz has of 2-4 seconds of buffer. + +config COMEDI_DEFAULT_BUF_MAXSIZE_KB + int "Comedi default maximum asynchronous buffer size in KiB" + default "20480" + ---help--- + This is the default maximum asynchronous buffer size which can + be requested by a userspace program without root privileges. + This is set to 20480 KiB so that a fast I/O card with 16 + channels running at 100 kHz has 2-4 seconds of buffer. + menuconfig COMEDI_MISC_DRIVERS - tristate "Comedi misc drivers" - depends on COMEDI - default N + bool "Comedi misc drivers" ---help--- Enable comedi misc drivers to be built @@ -34,7 +50,6 @@ config COMEDI_KCOMEDILIB config COMEDI_BOND tristate "Device bonding support" depends on COMEDI_KCOMEDILIB - default N ---help--- Enable support for a driver to 'bond' (merge) multiple subdevices from multiple devices together as one. @@ -45,7 +60,6 @@ config COMEDI_BOND config COMEDI_TEST tristate "Fake waveform generator support" select COMEDI_FC - default N ---help--- Enable support for the fake waveform generator. This driver is mainly for testing purposes, but can also be used to @@ -57,7 +71,6 @@ config COMEDI_TEST config COMEDI_PARPORT tristate "Parallel port support" - default N ---help--- Enable support for the standard parallel port. A cheap and easy way to get a few more digital I/O lines. Steal @@ -69,7 +82,6 @@ config COMEDI_PARPORT config COMEDI_SERIAL2002 tristate "Driver for serial connected hardware" - default N ---help--- Enable support for serial connected hardware @@ -78,19 +90,25 @@ config COMEDI_SERIAL2002 config COMEDI_SKEL tristate "Comedi skeleton driver" - default N ---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 + ---help--- + Enable support for SSV Embedded Systems DIL/Net-PC + + To compile this driver as a module, choose M here: the module will be + called ssv_dnp. + endif # COMEDI_MISC_DRIVERS menuconfig COMEDI_ISA_DRIVERS - tristate "Comedi ISA and PC/104 drivers" - depends on COMEDI && ISA - default N + bool "Comedi ISA and PC/104 drivers" ---help--- Enable comedi ISA and PC/104 drivers to be built @@ -98,21 +116,10 @@ menuconfig COMEDI_ISA_DRIVERS kernel: saying N will just cause the configurator to skip all the questions about ISA and PC/104 comedi drivers. -if COMEDI_ISA_DRIVERS && ISA - -config COMEDI_ACL7225B - tristate "ADlink NuDAQ ACL-7225b and compatibles support" - default N - ---help--- - Enable support for ADlink NuDAQ ACL-7225b and compatibles, - ADlink ACL-7225b (acl7225b), ICP P16R16DIO (p16r16dio) - - To compile this driver as a module, choose M here: the module will be - called acl7225b. +if COMEDI_ISA_DRIVERS config COMEDI_PCL711 tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support" - default N ---help--- Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112 @@ -122,26 +129,25 @@ config COMEDI_PCL711 config COMEDI_PCL724 tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO" select COMEDI_8255 - default N ---help--- - Enable support for Advantech PCL-724, PCL-722, PCL-731 and - ADlink ACL-7122, ACL-7124, PET-48DIO ISA cards + Enable support for ISA and PC/104 based 8255 digital i/o boards. This + driver provides a legacy comedi driver wrapper for the generic 8255 + support driver. - To compile this driver as a module, choose M here: the module will be - called pcl724. - -config COMEDI_PCL725 - tristate "Advantech PCL-725 and compatible ISA card support" - default N - ---help--- - Enable support for Advantech PCL-725 and compatible ISA cards. + Supported boards include: + Advantech PCL-724 24 channels + Advantech PCL-722 144 (or 96) channels + Advantech PCL-731 48 channels + ADlink ACL-7122 144 (or 96) channels + ADlink ACL-7124 24 channels + ADlink PET-48DIO 48 channels + WinSystems PCM-IO48 48 channels (PC/104) To compile this driver as a module, choose M here: the module will be - called pcl725. + called pcl724. config COMEDI_PCL726 tristate "Advantech PCL-726 and compatible ISA card support" - default N ---help--- Enable support for Advantech PCL-726 and compatible ISA cards. @@ -149,18 +155,31 @@ config COMEDI_PCL726 called pcl726. config COMEDI_PCL730 - tristate "Advantech PCL-730 and ADlink ACL-7130 ISA card support" - default N + tristate "Simple Digital I/O board support (8-bit ports)" ---help--- - Enable support for Advantech PCL-730, ICP ISO-730 and ADlink - ACL-7130 ISA cards + Enable support for various simple ISA or PC/104 Digital I/O boards. + These boards all use 8-bit I/O ports. + + Advantech PCL-730 iso - 16 in/16 out ttl - 16 in/16 out + ICP ISO-730 iso - 16 in/16 out ttl - 16 in/16 out + ADlink ACL-7130 iso - 16 in/16 out ttl - 16 in/16 out + Advantech PCM-3730 iso - 8 in/8 out ttl - 16 in/16 out + Advantech PCL-725 iso - 8 in/8 out + ICP P8R8-DIO iso - 8 in/8 out + ADlink ACL-7225b iso - 16 in/16 out + ICP P16R16-DIO iso - 16 in/16 out + Advantech PCL-733 iso - 32 in + Advantech PCL-734 iso - 32 out + Diamond Systems OPMM-1616-XT iso - 16 in/16 out + Diamond Systems PEARL-MM-P iso - 16 out To compile this driver as a module, choose M here: the module will be called pcl730. config COMEDI_PCL812 tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" - default N + 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, @@ -171,7 +190,8 @@ config COMEDI_PCL812 config COMEDI_PCL816 tristate "Advantech PCL-814 and PCL-816 ISA card support" - default N + depends on VIRT_TO_BUS && ISA_DMA_API + select COMEDI_FC ---help--- Enable support for Advantech PCL-814 and PCL-816 ISA cards @@ -180,7 +200,8 @@ config COMEDI_PCL816 config COMEDI_PCL818 tristate "Advantech PCL-718 and PCL-818 ISA card support" - default N + 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 @@ -191,25 +212,42 @@ config COMEDI_PCL818 config COMEDI_PCM3724 tristate "Advantech PCM-3724 PC/104 card support" select COMEDI_8255 - default N ---help--- Enable support for Advantech PCM-3724 PC/104 cards. To compile this driver as a module, choose M here: the module will be called pcm3724. -config COMEDI_PCM3730 - tristate "Advantech PCM-3730 and clone PC/104 board support" - default N +config COMEDI_AMPLC_DIO200_ISA + tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E" + select COMEDI_AMPLC_DIO200 ---help--- - Enable support for Advantech PCM-3730 and clone PC/104 boards + Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and + PC272E ISA DIO boards To compile this driver as a module, choose M here: the module will be - called pcm3730. + called amplc_dio200. + +config COMEDI_AMPLC_PC236_ISA + tristate "Amplicon PC36AT DIO board support" + select COMEDI_AMPLC_PC236 + ---help--- + Enable support for Amplicon PC36AT ISA DIO board. + + To compile this driver as a module, choose M here: the module will be + called amplc_pc236. + +config COMEDI_AMPLC_PC263_ISA + tristate "Amplicon PC263 relay board support" + ---help--- + Enable support for Amplicon PC263 ISA relay board. This board has + 16 reed relay output channels. + + To compile this driver as a module, choose M here: the module will be + called amplc_pc263. config COMEDI_RTI800 tristate "Analog Devices RTI-800/815 ISA card support" - default N ---help--- Enable support for Analog Devices RTI-800/815 ISA cards @@ -218,29 +256,48 @@ config COMEDI_RTI800 config COMEDI_RTI802 tristate "Analog Devices RTI-802 ISA card support" - default N ---help--- Enable support for Analog Devices RTI-802 ISA cards To compile this driver as a module, choose M here: the module will be called rti802. +config COMEDI_DAC02 + tristate "Keithley Metrabyte DAC02 compatible ISA card support" + ---help--- + Enable support for Keithley Metrabyte DAC02 compatible ISA cards. + + To compile this driver as a module, choose M here: the module will be + called dac02. + config COMEDI_DAS16M1 tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for Measurement Computing CIO-DAS16/M1 ISA cards. To compile this driver as a module, choose M here: the module will be called das16m1. +config COMEDI_DAS08_ISA + tristate "DAS-08 compatible ISA and PC/104 card support" + select COMEDI_DAS08 + ---help--- + Enable support for Keithley Metrabyte/ComputerBoards DAS08 + and compatible ISA and PC/104 cards: + Keithley Metrabyte/ComputerBoards DAS08, DAS08-PGM, DAS08-PGH, + DAS08-PGL, DAS08-AOH, DAS08-AOL, DAS08-AOM, DAS08/JR-AO, + DAS08/JR-16-AO, PC104-DAS08, DAS08/JR/16. + + To compile this driver as a module, choose M here: the module will be + called das08_isa. + config COMEDI_DAS16 tristate "DAS-16 compatible ISA and PC/104 card support" + depends on ISA_DMA_API select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for Keithley Metrabyte/ComputerBoards DAS16 and compatible ISA and PC/104 cards: @@ -257,7 +314,6 @@ config COMEDI_DAS16 config COMEDI_DAS800 tristate "DAS800 and compatible ISA card support" select COMEDI_FC - default N ---help--- Enable support for Keithley Metrabyte DAS800 and compatible ISA cards Keithley Metrabyte DAS-800, DAS-801, DAS-802 @@ -269,8 +325,8 @@ config COMEDI_DAS800 config COMEDI_DAS1800 tristate "DAS1800 and compatible ISA card support" + depends on VIRT_TO_BUS && ISA_DMA_API select COMEDI_FC - default N ---help--- Enable support for DAS1800 and compatible ISA cards Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO, @@ -284,7 +340,6 @@ config COMEDI_DAS1800 config COMEDI_DAS6402 tristate "DAS6402 and compatible ISA card support" - default N ---help--- Enable support for DAS6402 and compatible ISA cards Computerboards, Keithley Metrabyte DAS6402 and compatibles @@ -294,7 +349,6 @@ config COMEDI_DAS6402 config COMEDI_DT2801 tristate "Data Translation DT2801 ISA card support" - default N ---help--- Enable support for Data Translation DT2801 ISA cards @@ -303,7 +357,6 @@ config COMEDI_DT2801 config COMEDI_DT2811 tristate "Data Translation DT2811 ISA card support" - default N ---help--- Enable support for Data Translation DT2811 ISA cards @@ -312,7 +365,6 @@ config COMEDI_DT2811 config COMEDI_DT2814 tristate "Data Translation DT2814 ISA card support" - default N ---help--- Enable support for Data Translation DT2814 ISA cards @@ -321,7 +373,6 @@ config COMEDI_DT2814 config COMEDI_DT2815 tristate "Data Translation DT2815 ISA card support" - default N ---help--- Enable support for Data Translation DT2815 ISA cards @@ -330,7 +381,6 @@ config COMEDI_DT2815 config COMEDI_DT2817 tristate "Data Translation DT2817 ISA card support" - default N ---help--- Enable support for Data Translation DT2817 ISA cards @@ -340,7 +390,7 @@ config COMEDI_DT2817 config COMEDI_DT282X tristate "Data Translation DT2821 series and DT-EZ ISA card support" select COMEDI_FC - default N + depends on VIRT_TO_BUS && ISA_DMA_API ---help--- Enable support for Data Translation DT2821 series including DT-EZ DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI, @@ -352,16 +402,22 @@ config COMEDI_DT282X config COMEDI_DMM32AT tristate "Diamond Systems MM-32-AT PC/104 board support" - default N ---help--- Enable support for Diamond Systems MM-32-AT PC/104 boards To compile this driver as a module, choose M here: the module will be called dmm32at. +config COMEDI_UNIOXX5 + tristate "Fastwel UNIOxx-5 analog and digital io board support" + ---help--- + Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards + + To compile this driver as a module, choose M here: the module will be + called unioxx5. + config COMEDI_FL512 tristate "FL512 ISA card support" - default N ---help--- Enable support for FL512 ISA card @@ -371,7 +427,6 @@ config COMEDI_FL512 config COMEDI_AIO_AIO12_8 tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" select COMEDI_8255 - default N ---help--- Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board @@ -380,7 +435,6 @@ config COMEDI_AIO_AIO12_8 config COMEDI_AIO_IIRO_16 tristate "I/O Products PC/104 IIRO16 Board support" - default N ---help--- Enable support for I/O Products PC/104 IIRO16 Relay And Isolated Input Board @@ -388,9 +442,17 @@ config COMEDI_AIO_IIRO_16 To compile this driver as a module, choose M here: the module will be called aio_iiro_16. +config COMEDI_II_PCI20KC + tristate "Intelligent Instruments PCI-20001C carrier support" + ---help--- + Enable support for Intelligent Instruments PCI-20001C carrier + PCI-20001, PCI-20006 and PCI-20341 + + To compile this driver as a module, choose M here: the module will be + called ii_pci20kc. + config COMEDI_C6XDIGIO tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support" - default N ---help--- Enable support for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card @@ -400,7 +462,6 @@ config COMEDI_C6XDIGIO config COMEDI_MPC624 tristate "Micro/sys MPC-624 PC/104 board support" - default N ---help--- Enable support for Micro/sys MPC-624 PC/104 board @@ -409,7 +470,6 @@ config COMEDI_MPC624 config COMEDI_ADQ12B tristate "MicroAxial ADQ12-B data acquisition and control card support" - default N ---help--- Enable MicroAxial ADQ12-B daq and control card support. @@ -418,8 +478,8 @@ config COMEDI_ADQ12B config COMEDI_NI_AT_A2150 tristate "NI AT-A2150 ISA card support" - depends on COMEDI_NI_COMMON - default N + select COMEDI_FC + depends on VIRT_TO_BUS && ISA_DMA_API ---help--- Enable support for National Instruments AT-A2150 cards @@ -428,8 +488,6 @@ config COMEDI_NI_AT_A2150 config COMEDI_NI_AT_AO tristate "NI AT-AO-6/10 EISA card support" - depends on COMEDI_NI_COMMON - default N ---help--- Enable support for National Instruments AT-AO-6/10 cards @@ -438,9 +496,9 @@ config COMEDI_NI_AT_AO config COMEDI_NI_ATMIO tristate "NI AT-MIO E series ISA-PNP card support" - depends on ISAPNP && COMEDI_NI_TIO && COMEDI_NI_COMMON select COMEDI_8255 - default N + 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), @@ -451,19 +509,29 @@ config COMEDI_NI_ATMIO called ni_atmio. config COMEDI_NI_ATMIO16D - tristate "NI AT-MIO16/AT-MIO16D series ISA-PNP card support" - depends on ISAPNP && COMEDI_NI_COMMON + tristate "NI AT-MIO-16/AT-MIO-16D series ISA card support" select COMEDI_8255 - default N ---help--- - Enable support for National Instruments AT-MIO16/AT-MIO16D cards. + Enable support for National Instruments AT-MIO-16/AT-MIO-16D cards. To compile this driver as a module, choose M here: the module will be called ni_atmio16d. +config COMEDI_NI_LABPC_ISA + tristate "NI Lab-PC and compatibles ISA support" + select COMEDI_NI_LABPC + select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API && VIRT_TO_BUS + ---help--- + Enable support for National Instruments Lab-PC and compatibles + Lab-PC-1200, Lab-PC-1200AI, Lab-PC+. + Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has + not yet been added to the driver. + + To compile this driver as a module, choose M here: the module will be + called ni_labpc. + config COMEDI_PCMAD tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support" - default N ---help--- Enable support for Winsystems PCM-A/D12 and PCM-A/D16 PC/104 boards. @@ -472,7 +540,6 @@ config COMEDI_PCMAD config COMEDI_PCMDA12 tristate "Winsystems PCM-D/A-12 8-channel AO PC/104 board support" - default N ---help--- Enable support for Winsystems PCM-D/A-12 8-channel AO PC/104 boards. Note that the board is not ISA-PNP capable and thus needs the I/O @@ -483,7 +550,6 @@ config COMEDI_PCMDA12 config COMEDI_PCMMIO tristate "Winsystems PCM-MIO PC/104 board support" - default N ---help--- Enable support for Winsystems PCM-MIO multifunction PC/104 boards. @@ -492,7 +558,6 @@ config COMEDI_PCMMIO config COMEDI_PCMUIO tristate "Winsystems PCM-UIO48A and PCM-UIO96A PC/104 board support" - default N ---help--- Enable support for PCM-UIO48A and PCM-UIO96A PC/104 boards. @@ -501,42 +566,56 @@ config COMEDI_PCMUIO config COMEDI_MULTIQ3 tristate "Quanser Consulting MultiQ-3 ISA card support" - default N ---help--- Enable support for Quanser Consulting MultiQ-3 ISA cards To compile this driver as a module, choose M here: the module will be called multiq3. -config COMEDI_POC - tristate "Generic driver for very simple devices" - default N +config COMEDI_S526 + tristate "Sensoray s526 support" ---help--- - Enable generic support for very simple / POC (Piece of Crap) boards, - Keithley Metrabyte DAC-02 (dac02), Advantech PCL-733 (pcl733) and - PCL-734 (pcl734) + Enable support for Sensoray s526 To compile this driver as a module, choose M here: the module will be - called poc. + called s526. endif # COMEDI_ISA_DRIVERS menuconfig COMEDI_PCI_DRIVERS - tristate "Comedi PCI drivers" - depends on COMEDI && PCI - default N + bool "Comedi PCI drivers" + depends on PCI ---help--- - Enable comedi PCI drivers to be built + Enable support for comedi PCI drivers. - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about PCI comedi drivers. +if COMEDI_PCI_DRIVERS -if COMEDI_PCI_DRIVERS && PCI +config COMEDI_8255_PCI + tristate "Generic PCI based 8255 digital i/o board support" + select COMEDI_8255 + ---help--- + Enable support for PCI based 8255 digital i/o boards. This driver + provides a PCI wrapper around the generic 8255 driver. + + Supported boards: + ADlink - PCI-7224, PCI-7248, and PCI-7296 + Measurement Computing - PCI-DIO24, PCI-DIO24H, PCI-DIO48H and + PCI-DIO96H + National Instruments - PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, + PCI-6503B, PCI-6503X, and PXI-6503 + + To compile this driver as a module, choose M here: the module will + be called 8255_pci. + +config COMEDI_ADDI_WATCHDOG + tristate + ---help--- + Provides support for the watchdog subdevice found on many ADDI-DATA + boards. This module will be automatically selected when needed. The + module will be called addi_watchdog. config COMEDI_ADDI_APCI_035 tristate "ADDI-DATA APCI_035 support" - default N ---help--- Enable support for ADDI-DATA APCI_035 cards @@ -545,7 +624,6 @@ config COMEDI_ADDI_APCI_035 config COMEDI_ADDI_APCI_1032 tristate "ADDI-DATA APCI_1032 support" - default N ---help--- Enable support for ADDI-DATA APCI_1032 cards @@ -554,7 +632,6 @@ config COMEDI_ADDI_APCI_1032 config COMEDI_ADDI_APCI_1500 tristate "ADDI-DATA APCI_1500 support" - default N ---help--- Enable support for ADDI-DATA APCI_1500 cards @@ -562,17 +639,19 @@ config COMEDI_ADDI_APCI_1500 called addi_apci_1500. config COMEDI_ADDI_APCI_1516 - tristate "ADDI-DATA APCI_1516 support" - default N + tristate "ADDI-DATA APCI-1016/1516/2016 support" + select COMEDI_ADDI_WATCHDOG ---help--- - Enable support for ADDI-DATA APCI_1516 cards + Enable support for ADDI-DATA APCI-1016, APCI-1516 and APCI-2016 boards. + These are 16 channel, optically isolated, digital I/O boards. The 1516 + and 2016 boards also have a watchdog for resetting the outputs to "0". To compile this driver as a module, choose M here: the module will be called addi_apci_1516. config COMEDI_ADDI_APCI_1564 tristate "ADDI-DATA APCI_1564 support" - default N + select COMEDI_ADDI_WATCHDOG ---help--- Enable support for ADDI-DATA APCI_1564 cards @@ -581,25 +660,15 @@ config COMEDI_ADDI_APCI_1564 config COMEDI_ADDI_APCI_16XX tristate "ADDI-DATA APCI_16xx support" - default N ---help--- Enable support for ADDI-DATA APCI_16xx cards To compile this driver as a module, choose M here: the module will be called addi_apci_16xx. -config COMEDI_ADDI_APCI_2016 - tristate "ADDI-DATA APCI_2016 support" - default N - ---help--- - Enable support for ADDI-DATA APCI_2016 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_2016. - config COMEDI_ADDI_APCI_2032 tristate "ADDI-DATA APCI_2032 support" - default N + select COMEDI_ADDI_WATCHDOG ---help--- Enable support for ADDI-DATA APCI_2032 cards @@ -608,36 +677,25 @@ config COMEDI_ADDI_APCI_2032 config COMEDI_ADDI_APCI_2200 tristate "ADDI-DATA APCI_2200 support" - default N + select COMEDI_ADDI_WATCHDOG ---help--- Enable support for ADDI-DATA APCI_2200 cards To compile this driver as a module, choose M here: the module will be called addi_apci_2200. -config COMEDI_ADDI_APCI_3001 - tristate "ADDI-DATA APCI_3001 support" - select COMEDI_FC - default N - ---help--- - Enable support for ADDI-DATA APCI_3001 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_3001. - config COMEDI_ADDI_APCI_3120 - tristate "ADDI-DATA APCI_3520 support" + tristate "ADDI-DATA APCI_3120/3001 support" + depends on VIRT_TO_BUS select COMEDI_FC - default N ---help--- - Enable support for ADDI-DATA APCI_3520 cards + Enable support for ADDI-DATA APCI_3120/3001 cards To compile this driver as a module, choose M here: the module will be called addi_apci_3120. config COMEDI_ADDI_APCI_3501 tristate "ADDI-DATA APCI_3501 support" - default N ---help--- Enable support for ADDI-DATA APCI_3501 cards @@ -646,7 +704,6 @@ config COMEDI_ADDI_APCI_3501 config COMEDI_ADDI_APCI_3XXX tristate "ADDI-DATA APCI_3xxx support" - default N ---help--- Enable support for ADDI-DATA APCI_3xxx cards @@ -655,44 +712,25 @@ config COMEDI_ADDI_APCI_3XXX config COMEDI_ADL_PCI6208 tristate "ADLink PCI-6208A support" - select COMEDI_8255 - default N ---help--- Enable support for ADLink PCI-6208A cards To compile this driver as a module, choose M here: the module will be called adl_pci6208. -config COMEDI_ADL_PCI7230 - tristate "ADLink PCI-7230 digital io board support" - default N +config COMEDI_ADL_PCI7X3X + tristate "ADLink PCI-723X/743X isolated digital i/o board support" ---help--- - Enable support for ADlink PCI-7230 digital io board support + Enable support for ADlink PCI-723X/743X isolated digital i/o boards. + Supported boards include the 32-channel PCI-7230 (16 in/16 out), + PCI-7233 (32 in), and PCI-7234 (32 out) as well as the 64-channel + PCI-7432 (32 in/32 out), PCI-7433 (64 in), and PCI-7434 (64 out). To compile this driver as a module, choose M here: the module will be - called adl_pci7230. - -config COMEDI_ADL_PCI7296 - tristate "ADLink PCI-7296 96 ch. digital io board support" - default N - ---help--- - Enable support for ADlink PCI-7296 96 ch. digital io board support - - To compile this driver as a module, choose M here: the module will be - called adl_pci7296. - -config COMEDI_ADL_PCI7432 - tristate "ADLink PCI-7432 64 ch. isolated digital io board support" - default N - ---help--- - Enable support for ADlink PCI-7432 64 ch. isolated digital io board - - To compile this driver as a module, choose M here: the module will be - called adl_pci7432. + called adl_pci7x3x. config COMEDI_ADL_PCI8164 tristate "ADLink PCI-8164 4 Axes Motion Control board support" - default N ---help--- Enable support for ADlink PCI-8164 4 Axes Motion Control board @@ -702,7 +740,6 @@ config COMEDI_ADL_PCI8164 config COMEDI_ADL_PCI9111 tristate "ADLink PCI-9111HR support" select COMEDI_FC - default N ---help--- Enable support for ADlink PCI9111 cards @@ -712,7 +749,7 @@ config COMEDI_ADL_PCI9111 config COMEDI_ADL_PCI9118 tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support" select COMEDI_FC - default N + depends on VIRT_TO_BUS ---help--- Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards @@ -721,7 +758,7 @@ config COMEDI_ADL_PCI9118 config COMEDI_ADV_PCI1710 tristate "Advantech PCI-171x, PCI-1720 and PCI-1731 support" - default N + select COMEDI_FC ---help--- Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720 and PCI-1731 @@ -731,58 +768,65 @@ config COMEDI_ADV_PCI1710 config COMEDI_ADV_PCI1723 tristate "Advantech PCI-1723 support" - default N ---help--- Enable support for Advantech PCI-1723 cards To compile this driver as a module, choose M here: the module will be called adv_pci1723. +config COMEDI_ADV_PCI1724 + tristate "Advantech PCI-1724U support" + ---help--- + Enable support for Advantech PCI-1724U cards. These are 32-channel + analog output cards with voltage and current loop output ranges and + 14-bit resolution. + + To compile this driver as a module, choose M here: the module will be + called adv_pci1724. + config COMEDI_ADV_PCI_DIO tristate "Advantech PCI DIO card support" select COMEDI_8255 - default N ---help--- Enable support for Advantech PCI DIO cards - PCI-1730, PCI-1733, PCI-1734, PCI-1736UP, PCI-1750, PCI-1751, - PCI-1752, PCI-1753/E, PCI-1754, PCI-1756 and PCI-1762 + PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, + PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, PCI-1756, + PCI-1760 and PCI-1762 To compile this driver as a module, choose M here: the module will be called adv_pci_dio. -config COMEDI_AMPLC_DIO200 - tristate "Amplicon PC272E and PCI272 DIO board support" - select COMEDI_8255 - default N +config COMEDI_AMPLC_DIO200_PCI + tristate "Amplicon PCI215/PCI272/PCIe215/PCIe236/PCIe296 DIO support" + select COMEDI_AMPLC_DIO200 ---help--- - Enable support for Amplicon PC272E and PCI272 DIO boards + Enable support for Amplicon PCI215, PCI272, PCIe215, PCIe236 + and PCIe296 DIO boards. To compile this driver as a module, choose M here: the module will be - called amplc_dio200. + called amplc_dio200_pci. -config COMEDI_AMPLC_PC236 - tristate "Amplicon PC36AT and PCI236 DIO board support" - select COMEDI_8255 - default N +config COMEDI_AMPLC_PC236_PCI + tristate "Amplicon PCI236 DIO board support" + select COMEDI_AMPLC_PC236 ---help--- - Enable support for Amplicon PC36AT and PCI236 DIO boards + Enable support for Amplicon PCI236 DIO board. To compile this driver as a module, choose M here: the module will be called amplc_pc236. -config COMEDI_AMPLC_PC263 - tristate "Amplicon PC263 and PCI263 relay board support" - default N +config COMEDI_AMPLC_PC263_PCI + tristate "Amplicon PCI263 relay board support" ---help--- - Enable support for Amplicon PC263 and PCI263 relay boards + Enable support for Amplicon PCI263 relay board. This is a PCI board + with 16 reed relay output channels. To compile this driver as a module, choose M here: the module will be - called amplc_pc263. + called amplc_pci263. config COMEDI_AMPLC_PCI224 tristate "Amplicon PCI224 and PCI234 support" select COMEDI_FC - default N ---help--- Enable support for Amplicon PCI224 and PCI234 AO boards @@ -792,7 +836,6 @@ config COMEDI_AMPLC_PCI224 config COMEDI_AMPLC_PCI230 tristate "Amplicon PCI230 and PCI260 support" select COMEDI_8255 - default N ---help--- Enable support for Amplicon PCI230 and PCI260 Multifunction I/O boards @@ -802,16 +845,24 @@ config COMEDI_AMPLC_PCI230 config COMEDI_CONTEC_PCI_DIO tristate "Contec PIO1616L digital I/O board support" - default N ---help--- Enable support for the Contec PIO1616L digital I/O board To compile this driver as a module, choose M here: the module will be called contec_pci_dio. +config COMEDI_DAS08_PCI + tristate "DAS-08 PCI support" + select COMEDI_DAS08 + ---help--- + Enable support for PCI DAS-08 cards. + + To compile this driver as a module, choose M here: the module will be + called das08_pci. + config COMEDI_DT3000 tristate "Data Translation DT3000 series support" - default N + select COMEDI_FC ---help--- Enable support for Data Translation DT3000 series DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and @@ -820,19 +871,18 @@ config COMEDI_DT3000 To compile this driver as a module, choose M here: the module will be called dt3000. -config COMEDI_UNIOXX5 - tristate "Fastwel UNIOxx-5 analog and digital io board support" - default N +config COMEDI_DYNA_PCI10XX + tristate "Dynalog PCI DAQ series support" ---help--- - Enable support for Fastwel UNIOxx-5 (analog and digital i/o) boards + Enable support for Dynalog PCI DAQ series + PCI-1050 To compile this driver as a module, choose M here: the module will be - called unioxx5. + called dyna_pci10xx. config COMEDI_GSC_HPDI tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support" select COMEDI_FC - default N ---help--- Enable support for General Standards Corporation high speed parallel digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32. @@ -841,29 +891,23 @@ config COMEDI_GSC_HPDI To compile this driver as a module, choose M here: the module will be called gsc_hpdi. +config COMEDI_MF6X4 + tristate "Humusoft MF634 and MF624 DAQ Card support" + ---help--- + This driver supports both Humusoft MF634 and MF624 Data acquisition + cards. The legacy Humusoft MF614 card is not supported. + config COMEDI_ICP_MULTI tristate "Inova ICP_MULTI support" - default N ---help--- Enable support for Inova ICP_MULTI card To compile this driver as a module, choose M here: the module will be called icp_multi. -config COMEDI_II_PCI20KC - tristate "Intelligent Instruments PCI-20001C carrier support" - default N - ---help--- - Enable support for Intelligent Instruments PCI-20001C carrier - PCI-20001, PCI-20006 and PCI-20341 - - To compile this driver as a module, choose M here: the module will be - called ii_pci20kc. - config COMEDI_DAQBOARD2000 tristate "IOtech DAQboard/2000 support" select COMEDI_8255 - default N ---help--- Enable support for the IOtech DAQboard/2000 @@ -872,7 +916,6 @@ config COMEDI_DAQBOARD2000 config COMEDI_JR3_PCI tristate "JR3/PCI force sensor board support" - default N ---help--- Enable support for JR3/PCI force sensor boards @@ -881,7 +924,6 @@ config COMEDI_JR3_PCI config COMEDI_KE_COUNTER tristate "Kolter-Electronic PCI Counter 1 card support" - default N ---help--- Enable support for Kolter-Electronic PCI Counter 1 cards @@ -892,7 +934,6 @@ config COMEDI_CB_PCIDAS64 tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support" select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 series with the PLX 9080 PCI controller @@ -904,7 +945,6 @@ config COMEDI_CB_PCIDAS tristate "MeasurementComputing PCI-DAS support" select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DAS with AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr, @@ -917,7 +957,6 @@ config COMEDI_CB_PCIDAS config COMEDI_CB_PCIDDA tristate "MeasurementComputing PCI-DDA series support" select COMEDI_8255 - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI-DDA series: PCI-DDA08/12, PCI-DDA04/12, PCI-DDA02/12, PCI-DDA08/16, @@ -926,21 +965,9 @@ config COMEDI_CB_PCIDDA To compile this driver as a module, choose M here: the module will be called cb_pcidda. -config COMEDI_CB_PCIDIO - tristate "MeasurementComputing PCI-DIO series support" - select COMEDI_8255 - default N - ---help--- - Enable support for ComputerBoards/MeasurementComputing PCI-DIO series - PCI-DIO24, PCI-DIO24H and PCI-DIO48H - - To compile this driver as a module, choose M here: the module will be - called cb_pcidio. - config COMEDI_CB_PCIMDAS tristate "MeasurementComputing PCIM-DAS1602/16 support" select COMEDI_8255 - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCI Migration series PCIM-DAS1602/16 @@ -951,7 +978,6 @@ config COMEDI_CB_PCIMDAS config COMEDI_CB_PCIMDDA tristate "MeasurementComputing PCIM-DDA06-16 support" select COMEDI_8255 - default N ---help--- Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16 @@ -960,7 +986,6 @@ config COMEDI_CB_PCIMDDA config COMEDI_ME4000 tristate "Meilhaus ME-4000 support" - default N ---help--- Enable support for Meilhaus PCI data acquisition cards ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is @@ -970,7 +995,6 @@ config COMEDI_ME4000 config COMEDI_ME_DAQ tristate "Meilhaus ME-2000i, ME-2600i, ME-3000vm1 support" - default N ---help--- Enable support for Meilhaus PCI data acquisition cards ME-2000i, ME-2600i and ME-3000vm1 @@ -980,8 +1004,6 @@ config COMEDI_ME_DAQ config COMEDI_NI_6527 tristate "NI 6527 support" - depends on COMEDI_MITE - default N ---help--- Enable support for the National Instruments 6527 PCI card @@ -990,8 +1012,8 @@ config COMEDI_NI_6527 config COMEDI_NI_65XX tristate "NI 65xx static dio PCI card support" - depends on COMEDI_MITE - default N + depends on HAS_DMA + select COMEDI_MITE ---help--- Enable support for National Instruments 65xx static dio boards. Supported devices: National Instruments PCI-6509 (ni_65xx), @@ -1004,46 +1026,54 @@ config COMEDI_NI_65XX config COMEDI_NI_660X tristate "NI 660x counter/timer PCI card support" - depends on COMEDI_NI_TIO && COMEDI_NI_COMMON - default N + depends on HAS_DMA + select COMEDI_NI_TIOCMD ---help--- Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602, - PXI-6602 and PXI-6608. + PXI-6602, PXI-6608 and PXI-6624. To compile this driver as a module, choose M here: the module will be called ni_660x. config COMEDI_NI_670X tristate "NI 670x PCI card support" - depends on COMEDI_MITE - default N + depends on HAS_DMA + select COMEDI_MITE ---help--- Enable support for National Instruments PCI-6703 and PCI-6704 To compile this driver as a module, choose M here: the module will be called ni_670x. +config COMEDI_NI_LABPC_PCI + tristate "NI Lab-PC PCI-1200 support" + depends on HAS_DMA + select COMEDI_NI_LABPC + select COMEDI_MITE + ---help--- + Enable support for National Instruments Lab-PC PCI-1200. + + To compile this driver as a module, choose M here: the module will be + called ni_labpc_pci. + config COMEDI_NI_PCIDIO - tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support" - depends on COMEDI_MITE + tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support" + depends on HAS_DMA + select COMEDI_MITE select COMEDI_8255 - default N ---help--- Enable support for National Instruments PCI-DIO-32HS, PXI-6533, - PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X, - PXI-6503, PCI-6533 and PCI-6534 - The DIO-96 appears as four 8255 subdevices. See the 8255 - driver notes for details. + PCI-6533 and PCI-6534 To compile this driver as a module, choose M here: the module will be called ni_pcidio. config COMEDI_NI_PCIMIO tristate "NI PCI-MIO-E series and M series support" - depends on COMEDI_NI_TIO && COMEDI_NI_COMMON + depends on HAS_DMA + select COMEDI_NI_TIOCMD select COMEDI_8255 select COMEDI_FC - default N ---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, @@ -1061,60 +1091,44 @@ config COMEDI_NI_PCIMIO config COMEDI_RTD520 tristate "Real Time Devices PCI4520/DM7520 support" - select COMEDI_8255 - default N ---help--- Enable support for Real Time Devices PCI4520/DM7520 To compile this driver as a module, choose M here: the module will be called rtd520. -config COMEDI_S526 - tristate "Sensoray s526 support" - default N - ---help--- - Enable support for Sensoray s526 - - To compile this driver as a module, choose M here: the module will be - called s526. - config COMEDI_S626 tristate "Sensoray 626 support" select COMEDI_FC - default N ---help--- Enable support for Sensoray 626 To compile this driver as a module, choose M here: the module will be called s626. -config COMEDI_SSV_DNP - tristate "SSV Embedded Systems DIL/Net-PC support" - default N - ---help--- - Enable support for SSV Embedded Systems DIL/Net-PC +config COMEDI_MITE + depends on HAS_DMA + select COMEDI_FC + tristate - To compile this driver as a module, choose M here: the module will be - called ssv_dnp. +config COMEDI_NI_TIOCMD + tristate + depends on HAS_DMA + select COMEDI_NI_TIO + select COMEDI_MITE endif # COMEDI_PCI_DRIVERS menuconfig COMEDI_PCMCIA_DRIVERS - tristate "Comedi PCMCIA drivers" - depends on COMEDI && (PCMCIA || PCCARD) - default N + bool "Comedi PCMCIA drivers" + depends on PCMCIA ---help--- - Enable comedi PCMCIA and PCCARD drivers to be built + Enable support for comedi PCMCIA drivers. - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about PCMCIA comedi drivers. - -if COMEDI_PCMCIA_DRIVERS && PCMCIA +if COMEDI_PCMCIA_DRIVERS config COMEDI_CB_DAS16_CS tristate "CB DAS16 series PCMCIA support" - default N ---help--- Enable support for the ComputerBoards/MeasurementComputing PCMCIA cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16 @@ -1125,7 +1139,6 @@ config COMEDI_CB_DAS16_CS config COMEDI_DAS08_CS tristate "CB DAS08 PCMCIA support" select COMEDI_DAS08 - default N ---help--- Enable support for the ComputerBoards/MeasurementComputing DAS-08 PCMCIA card @@ -1135,8 +1148,6 @@ config COMEDI_DAS08_CS config COMEDI_NI_DAQ_700_CS tristate "NI DAQCard-700 PCMCIA support" - depends on COMEDI_NI_COMMON - default N ---help--- Enable support for the National Instruments PCMCIA DAQCard-700 DIO @@ -1145,9 +1156,7 @@ config COMEDI_NI_DAQ_700_CS config COMEDI_NI_DAQ_DIO24_CS tristate "NI DAQ-Card DIO-24 PCMCIA support" - depends on COMEDI_NI_COMMON select COMEDI_8255 - default N ---help--- Enable support for the National Instruments PCMCIA DAQ-Card DIO-24 @@ -1156,8 +1165,7 @@ config COMEDI_NI_DAQ_DIO24_CS config COMEDI_NI_LABPC_CS tristate "NI DAQCard-1200 PCMCIA support" - depends on COMEDI_NI_LABPC - default N + select COMEDI_NI_LABPC ---help--- Enable support for the National Instruments PCMCIA DAQCard-1200 @@ -1166,10 +1174,9 @@ config COMEDI_NI_LABPC_CS config COMEDI_NI_MIO_CS tristate "NI DAQCard E series PCMCIA support" - depends on COMEDI_NI_TIO && COMEDI_NI_COMMON + select COMEDI_NI_TIO select COMEDI_8255 select COMEDI_FC - default N ---help--- Enable support for the National Instruments PCMCIA DAQCard E series DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E @@ -1180,7 +1187,7 @@ config COMEDI_NI_MIO_CS config COMEDI_QUATECH_DAQP_CS tristate "Quatech DAQP PCMCIA data capture card support" - default N + select COMEDI_FC ---help--- Enable support for the Quatech DAQP PCMCIA data capture cards DAQP-208 and DAQP-308 @@ -1191,21 +1198,15 @@ config COMEDI_QUATECH_DAQP_CS endif # COMEDI_PCMCIA_DRIVERS menuconfig COMEDI_USB_DRIVERS - tristate "Comedi USB drivers" - depends on COMEDI && USB - default N + bool "Comedi USB drivers" + depends on USB ---help--- - Enable comedi USB drivers to be built + Enable support for comedi USB drivers. - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about USB comedi drivers. - -if COMEDI_USB_DRIVERS && USB +if COMEDI_USB_DRIVERS config COMEDI_DT9812 tristate "DataTranslation DT9812 USB module support" - default N ---help--- Enable support for the Data Translation DT9812 USB module @@ -1213,11 +1214,9 @@ config COMEDI_DT9812 called dt9812. config COMEDI_USBDUX - tristate "ITL USBDUX support" - default N + tristate "ITL USB-DUX-D support" ---help--- - Enable support for the University of Stirling USB DAQ and INCITE - Technology Limited driver + Enable support for the Incite Technology Ltd USB-DUX-D Board To compile this driver as a module, choose M here: the module will be called usbdux. @@ -1225,17 +1224,23 @@ config COMEDI_USBDUX config COMEDI_USBDUXFAST tristate "ITL USB-DUXfast support" select COMEDI_FC - default N ---help--- - Enable support for the University of Stirling USB-DUXfast and INCITE - Technology Limited driver + Enable support for the Incite Technology Ltd USB-DUXfast Board To compile this driver as a module, choose M here: the module will be called usbduxfast. +config COMEDI_USBDUXSIGMA + tristate "ITL USB-DUXsigma support" + select COMEDI_FC + ---help--- + Enable support for the Incite Technology Ltd USB-DUXsigma Board + + To compile this driver as a module, choose M here: the module will be + called usbduxsigma. + config COMEDI_VMK80XX tristate "Velleman VM110/VM140 USB Board support" - default N ---help--- Build the Velleman USB Board Low-Level Driver supporting the K8055/K8061 aka VM110/VM140 devices @@ -1245,64 +1250,8 @@ config COMEDI_VMK80XX endif # COMEDI_USB_DRIVERS -menuconfig COMEDI_NI_COMMON - tristate "Comedi National Instruments card support" - depends on COMEDI - default N - ---help--- - Enable comedi support for National Instruments cards. - Modules in this section are used by many comedi NI drivers. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about National Instruments cards. - -if COMEDI_NI_COMMON - -config COMEDI_MITE - tristate "NI Mite PCI interface chip support" - depends on PCI - default N - ---help--- - Enable support for National Instruments Mite PCI interface chip - - To compile this driver as a module, choose M here: the module will be - called mite. - -config COMEDI_NI_TIO - tristate "NI general purpose counter support" - depends on COMEDI_MITE - default N - ---help--- - Enable support for National Instruments general purpose counters. - This module is not used directly by end-users. Rather, it - is used by other drivers (for example ni_660x and ni_pcimio) - to provide support for NI's general purpose counters. - - To compile this driver as a modules, choose M here: two modules will - be build: ni_tio and ni_tiocmd. - -config COMEDI_NI_LABPC - tristate "NI Lab-PC and compatibles ISA and PCI support" - depends on COMEDI_MITE - select COMEDI_8255 - select COMEDI_FC - default N - ---help--- - Enable support for National Instruments Lab-PC and compatibles - Lab-PC-1200, Lab-PC-1200AI, Lab-PC+ and PCI-1200. - Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has - not yet been added to the driver. - - To compile this driver as a module, choose M here: the module will be - called ni_labpc. - -endif # COMEDI_NI_COMMON - config COMEDI_8255 tristate "Generic 8255 support" - depends on COMEDI - default N ---help--- Enable generic 8255 support. @@ -1310,34 +1259,35 @@ config COMEDI_8255 that has an 8255 chip. For multifunction boards, the main driver will configure the 8255 subdevice automatically. - Note that most PCI 8255 boards do NOT work with this driver, and - need a separate driver as a wrapper. + Note that most PCI based 8255 boards use the 8255_pci driver as a + wrapper around this driver. To compile this driver as a module, choose M here: the module will be called 8255. +config COMEDI_FC + tristate + +config COMEDI_AMPLC_DIO200 + tristate + +config COMEDI_AMPLC_PC236 + tristate + select COMEDI_8255 + config COMEDI_DAS08 - tristate "DAS-08 compatible support" - depends on COMEDI + tristate select COMEDI_8255 - default N - ---help--- - Enable support for DAS08 and compatible ISA, PC/104 and PCI cards. - Note that PCMCIA DAS08 cards are not directly supported by this - driver, and need a separate driver as a wrapper. +config COMEDI_NI_LABPC + tristate + select COMEDI_8255 + select COMEDI_FC - To compile this driver as a module, choose M here: the module will be - called das08. +config COMEDI_NI_LABPC_ISADMA + tristate -config COMEDI_FC - tristate "Comedi shared functions for low-level driver support" - depends on COMEDI - default N - ---help--- - Enable support for shared functions for low-level drivers. - This module is not used directly by end-users. Rather, it - is used by many other comedi drivers. +config COMEDI_NI_TIO + tristate - To compile this driver as a module, choose M here: the module will be - called comedi_fc. +endif # COMEDI diff --git a/drivers/staging/comedi/Makefile b/drivers/staging/comedi/Makefile index 8dbd306fef8..fae2d909000 100644 --- a/drivers/staging/comedi/Makefile +++ b/drivers/staging/comedi/Makefile @@ -1,11 +1,14 @@ -obj-$(CONFIG_COMEDI) += comedi.o +ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG -obj-$(CONFIG_COMEDI) += kcomedilib/ -obj-$(CONFIG_COMEDI) += drivers/ +comedi-y := comedi_fops.o range.o drivers.o \ + comedi_buf.o +comedi-$(CONFIG_COMEDI_PCI_DRIVERS) += comedi_pci.o +comedi-$(CONFIG_COMEDI_PCMCIA_DRIVERS) += comedi_pcmcia.o +comedi-$(CONFIG_COMEDI_USB_DRIVERS) += comedi_usb.o +comedi-$(CONFIG_PROC_FS) += proc.o +comedi-$(CONFIG_COMPAT) += comedi_compat32.o -comedi-y := \ - comedi_fops.o \ - proc.o \ - range.o \ - drivers.o \ - comedi_compat32.o \ +obj-$(CONFIG_COMEDI) += comedi.o + +obj-$(CONFIG_COMEDI) += kcomedilib/ +obj-$(CONFIG_COMEDI) += drivers/ diff --git a/drivers/staging/comedi/TODO b/drivers/staging/comedi/TODO index b10f739b7e3..b68fbdb5eeb 100644 --- a/drivers/staging/comedi/TODO +++ b/drivers/staging/comedi/TODO @@ -3,10 +3,9 @@ TODO: - Lindent - remove all wrappers - audit userspace interface - - reserve major number - cleanup the individual comedi drivers as well Please send patches to Greg Kroah-Hartman <greg@kroah.com> and copy: Ian Abbott <abbotti@mev.co.uk> - Frank Mori Hess <fmhess@users.sourceforge.net> + H Hartley Sweeten <hsweeten@visionengravers.com> diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h index 6c900e2756f..6bbbe5b0895 100644 --- a/drivers/staging/comedi/comedi.h +++ b/drivers/staging/comedi/comedi.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDI_H @@ -41,7 +36,17 @@ /* number of config options in the config structure */ #define COMEDI_NDEVCONFOPTS 32 -/*length of nth chunk of firmware data*/ + +/* + * NOTE: 'comedi_config --init-data' is deprecated + * + * The following indexes in the config options were used by + * comedi_config to pass firmware blobs from user space to the + * comedi drivers. The request_firmware() hotplug interface is + * now used by all comedi drivers instead. + */ + +/* length of nth chunk of firmware data -*/ #define COMEDI_DEVCONF_AUX_DATA3_LENGTH 25 #define COMEDI_DEVCONF_AUX_DATA2_LENGTH 26 #define COMEDI_DEVCONF_AUX_DATA1_LENGTH 27 @@ -208,92 +213,130 @@ /* subdevice types */ - enum comedi_subdevice_type { - COMEDI_SUBD_UNUSED, /* unused by driver */ - COMEDI_SUBD_AI, /* analog input */ - COMEDI_SUBD_AO, /* analog output */ - COMEDI_SUBD_DI, /* digital input */ - COMEDI_SUBD_DO, /* digital output */ - COMEDI_SUBD_DIO, /* digital input/output */ - COMEDI_SUBD_COUNTER, /* counter */ - COMEDI_SUBD_TIMER, /* timer */ - COMEDI_SUBD_MEMORY, /* memory, EEPROM, DPRAM */ - COMEDI_SUBD_CALIB, /* calibration DACs */ - COMEDI_SUBD_PROC, /* processor, DSP */ - COMEDI_SUBD_SERIAL, /* serial IO */ - COMEDI_SUBD_PWM /* PWM */ - }; +enum comedi_subdevice_type { + COMEDI_SUBD_UNUSED, /* unused by driver */ + COMEDI_SUBD_AI, /* analog input */ + COMEDI_SUBD_AO, /* analog output */ + COMEDI_SUBD_DI, /* digital input */ + COMEDI_SUBD_DO, /* digital output */ + COMEDI_SUBD_DIO, /* digital input/output */ + COMEDI_SUBD_COUNTER, /* counter */ + COMEDI_SUBD_TIMER, /* timer */ + COMEDI_SUBD_MEMORY, /* memory, EEPROM, DPRAM */ + COMEDI_SUBD_CALIB, /* calibration DACs */ + COMEDI_SUBD_PROC, /* processor, DSP */ + COMEDI_SUBD_SERIAL, /* serial IO */ + COMEDI_SUBD_PWM /* PWM */ +}; /* configuration instructions */ - enum configuration_ids { - INSN_CONFIG_DIO_INPUT = 0, - INSN_CONFIG_DIO_OUTPUT = 1, - INSN_CONFIG_DIO_OPENDRAIN = 2, - INSN_CONFIG_ANALOG_TRIG = 16, +enum configuration_ids { + INSN_CONFIG_DIO_INPUT = 0, + INSN_CONFIG_DIO_OUTPUT = 1, + INSN_CONFIG_DIO_OPENDRAIN = 2, + INSN_CONFIG_ANALOG_TRIG = 16, /* INSN_CONFIG_WAVEFORM = 17, */ /* INSN_CONFIG_TRIG = 18, */ /* INSN_CONFIG_COUNTER = 19, */ - INSN_CONFIG_ALT_SOURCE = 20, - INSN_CONFIG_DIGITAL_TRIG = 21, - INSN_CONFIG_BLOCK_SIZE = 22, - INSN_CONFIG_TIMER_1 = 23, - INSN_CONFIG_FILTER = 24, - INSN_CONFIG_CHANGE_NOTIFY = 25, - - /*ALPHA*/ INSN_CONFIG_SERIAL_CLOCK = 26, - INSN_CONFIG_BIDIRECTIONAL_DATA = 27, - INSN_CONFIG_DIO_QUERY = 28, - INSN_CONFIG_PWM_OUTPUT = 29, - INSN_CONFIG_GET_PWM_OUTPUT = 30, - INSN_CONFIG_ARM = 31, - INSN_CONFIG_DISARM = 32, - INSN_CONFIG_GET_COUNTER_STATUS = 33, - INSN_CONFIG_RESET = 34, - /* Use CTR as single pulsegenerator */ - INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001, - /* Use CTR as pulsetraingenerator */ - INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002, - /* Use the counter as encoder */ - INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003, - INSN_CONFIG_SET_GATE_SRC = 2001, /* Set gate source */ - INSN_CONFIG_GET_GATE_SRC = 2002, /* Get gate source */ - /* Set master clock source */ - INSN_CONFIG_SET_CLOCK_SRC = 2003, - INSN_CONFIG_GET_CLOCK_SRC = 2004, /* Get master clock source */ - INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */ - /* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */ - /* Get size in bytes of subdevice's on-board fifos used during - * streaming input/output */ - INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006, - INSN_CONFIG_SET_COUNTER_MODE = 4097, - /* INSN_CONFIG_8254_SET_MODE is deprecated */ - INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE, - INSN_CONFIG_8254_READ_STATUS = 4098, - INSN_CONFIG_SET_ROUTING = 4099, - INSN_CONFIG_GET_ROUTING = 4109, -/* PWM */ - INSN_CONFIG_PWM_SET_PERIOD = 5000, /* sets frequency */ - INSN_CONFIG_PWM_GET_PERIOD = 5001, /* gets frequency */ - INSN_CONFIG_GET_PWM_STATUS = 5002, /* is it running? */ - /* sets H bridge: duty cycle and sign bit for a relay at the - * same time */ - INSN_CONFIG_PWM_SET_H_BRIDGE = 5003, - /* gets H bridge data: duty cycle and the sign bit */ - INSN_CONFIG_PWM_GET_H_BRIDGE = 5004 - }; - - enum comedi_io_direction { - COMEDI_INPUT = 0, - COMEDI_OUTPUT = 1, - COMEDI_OPENDRAIN = 2 - }; - - enum comedi_support_level { - COMEDI_UNKNOWN_SUPPORT = 0, - COMEDI_SUPPORTED, - COMEDI_UNSUPPORTED - }; + INSN_CONFIG_ALT_SOURCE = 20, + INSN_CONFIG_DIGITAL_TRIG = 21, + INSN_CONFIG_BLOCK_SIZE = 22, + INSN_CONFIG_TIMER_1 = 23, + INSN_CONFIG_FILTER = 24, + INSN_CONFIG_CHANGE_NOTIFY = 25, + + INSN_CONFIG_SERIAL_CLOCK = 26, /*ALPHA*/ + INSN_CONFIG_BIDIRECTIONAL_DATA = 27, + INSN_CONFIG_DIO_QUERY = 28, + INSN_CONFIG_PWM_OUTPUT = 29, + INSN_CONFIG_GET_PWM_OUTPUT = 30, + INSN_CONFIG_ARM = 31, + INSN_CONFIG_DISARM = 32, + INSN_CONFIG_GET_COUNTER_STATUS = 33, + INSN_CONFIG_RESET = 34, + /* Use CTR as single pulsegenerator */ + INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001, + /* Use CTR as pulsetraingenerator */ + INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002, + /* Use the counter as encoder */ + INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003, + INSN_CONFIG_SET_GATE_SRC = 2001, /* Set gate source */ + INSN_CONFIG_GET_GATE_SRC = 2002, /* Get gate source */ + /* Set master clock source */ + INSN_CONFIG_SET_CLOCK_SRC = 2003, + INSN_CONFIG_GET_CLOCK_SRC = 2004, /* Get master clock source */ + INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */ + /* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */ + /* Get size in bytes of subdevice's on-board fifos used during + * streaming input/output */ + INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006, + INSN_CONFIG_SET_COUNTER_MODE = 4097, + /* INSN_CONFIG_8254_SET_MODE is deprecated */ + INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE, + INSN_CONFIG_8254_READ_STATUS = 4098, + INSN_CONFIG_SET_ROUTING = 4099, + INSN_CONFIG_GET_ROUTING = 4109, + /* PWM */ + INSN_CONFIG_PWM_SET_PERIOD = 5000, /* sets frequency */ + INSN_CONFIG_PWM_GET_PERIOD = 5001, /* gets frequency */ + INSN_CONFIG_GET_PWM_STATUS = 5002, /* is it running? */ + /* sets H bridge: duty cycle and sign bit for a relay at the + * same time */ + INSN_CONFIG_PWM_SET_H_BRIDGE = 5003, + /* gets H bridge data: duty cycle and the sign bit */ + INSN_CONFIG_PWM_GET_H_BRIDGE = 5004 +}; + +/* + * Settings for INSN_CONFIG_DIGITAL_TRIG: + * data[0] = INSN_CONFIG_DIGITAL_TRIG + * data[1] = trigger ID + * data[2] = configuration operation + * data[3] = configuration parameter 1 + * data[4] = configuration parameter 2 + * data[5] = configuration parameter 3 + * + * operation parameter 1 parameter 2 parameter 3 + * --------------------------------- ----------- ----------- ----------- + * COMEDI_DIGITAL_TRIG_DISABLE + * COMEDI_DIGITAL_TRIG_ENABLE_EDGES left-shift rising-edges falling-edges + * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS left-shift high-levels low-levels + * + * COMEDI_DIGITAL_TRIG_DISABLE returns the trigger to its default, inactive, + * unconfigured state. + * + * COMEDI_DIGITAL_TRIG_ENABLE_EDGES sets the rising and/or falling edge inputs + * that each can fire the trigger. + * + * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS sets a combination of high and/or low + * level inputs that can fire the trigger. + * + * "left-shift" is useful if the trigger has more than 32 inputs to specify the + * first input for this configuration. + * + * Some sequences of INSN_CONFIG_DIGITAL_TRIG instructions may have a (partly) + * accumulative effect, depending on the low-level driver. This is useful + * when setting up a trigger that has more than 32 inputs or has a combination + * of edge and level triggered inputs. + */ +enum comedi_digital_trig_op { + COMEDI_DIGITAL_TRIG_DISABLE = 0, + COMEDI_DIGITAL_TRIG_ENABLE_EDGES = 1, + COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = 2 +}; + +enum comedi_io_direction { + COMEDI_INPUT = 0, + COMEDI_OUTPUT = 1, + COMEDI_OPENDRAIN = 2 +}; + +enum comedi_support_level { + COMEDI_UNKNOWN_SUPPORT = 0, + COMEDI_SUPPORTED, + COMEDI_UNSUPPORTED +}; /* ioctls */ @@ -317,133 +360,133 @@ /* structures */ - struct comedi_trig { - unsigned int subdev; /* subdevice */ - unsigned int mode; /* mode */ - unsigned int flags; - unsigned int n_chan; /* number of channels */ - unsigned int *chanlist; /* channel/range list */ - short *data; /* data list, size depends on subd flags */ - unsigned int n; /* number of scans */ - unsigned int trigsrc; - unsigned int trigvar; - unsigned int trigvar1; - unsigned int data_len; - unsigned int unused[3]; - }; - - struct comedi_insn { - unsigned int insn; - unsigned int n; - unsigned int __user *data; - unsigned int subdev; - unsigned int chanspec; - unsigned int unused[3]; - }; - - struct comedi_insnlist { - unsigned int n_insns; - struct comedi_insn __user *insns; - }; - - struct comedi_cmd { - unsigned int subdev; - unsigned int flags; - - unsigned int start_src; - unsigned int start_arg; - - unsigned int scan_begin_src; - unsigned int scan_begin_arg; - - unsigned int convert_src; - unsigned int convert_arg; - - unsigned int scan_end_src; - unsigned int scan_end_arg; - - unsigned int stop_src; - unsigned int stop_arg; - - unsigned int __user *chanlist; /* channel/range list */ - unsigned int chanlist_len; - - short __user *data; /* data list, size depends on subd flags */ - unsigned int data_len; - }; - - struct comedi_chaninfo { - unsigned int subdev; - unsigned int __user *maxdata_list; - unsigned int __user *flaglist; - unsigned int __user *rangelist; - unsigned int unused[4]; - }; - - struct comedi_rangeinfo { - unsigned int range_type; - void __user *range_ptr; - }; - - struct comedi_krange { - int min; /* fixed point, multiply by 1e-6 */ - int max; /* fixed point, multiply by 1e-6 */ - unsigned int flags; - }; - - struct comedi_subdinfo { - unsigned int type; - unsigned int n_chan; - unsigned int subd_flags; - unsigned int timer_type; - unsigned int len_chanlist; - unsigned int maxdata; - unsigned int flags; /* channel flags */ - unsigned int range_type; /* lookup in kernel */ - unsigned int settling_time_0; - /* see support_level enum for values */ - unsigned insn_bits_support; - unsigned int unused[8]; - }; - - struct comedi_devinfo { - unsigned int version_code; - unsigned int n_subdevs; - char driver_name[COMEDI_NAMELEN]; - char board_name[COMEDI_NAMELEN]; - int read_subdevice; - int write_subdevice; - int unused[30]; - }; - - struct comedi_devconfig { - char board_name[COMEDI_NAMELEN]; - int options[COMEDI_NDEVCONFOPTS]; - }; - - struct comedi_bufconfig { - unsigned int subdevice; - unsigned int flags; - - unsigned int maximum_size; - unsigned int size; - - unsigned int unused[4]; - }; - - struct comedi_bufinfo { - unsigned int subdevice; - unsigned int bytes_read; - - unsigned int buf_write_ptr; - unsigned int buf_read_ptr; - unsigned int buf_write_count; - unsigned int buf_read_count; - - unsigned int bytes_written; - - unsigned int unused[4]; - }; +struct comedi_trig { + unsigned int subdev; /* subdevice */ + unsigned int mode; /* mode */ + unsigned int flags; + unsigned int n_chan; /* number of channels */ + unsigned int *chanlist; /* channel/range list */ + short *data; /* data list, size depends on subd flags */ + unsigned int n; /* number of scans */ + unsigned int trigsrc; + unsigned int trigvar; + unsigned int trigvar1; + unsigned int data_len; + unsigned int unused[3]; +}; + +struct comedi_insn { + unsigned int insn; + unsigned int n; + unsigned int __user *data; + unsigned int subdev; + unsigned int chanspec; + unsigned int unused[3]; +}; + +struct comedi_insnlist { + unsigned int n_insns; + struct comedi_insn __user *insns; +}; + +struct comedi_cmd { + unsigned int subdev; + unsigned int flags; + + unsigned int start_src; + unsigned int start_arg; + + unsigned int scan_begin_src; + unsigned int scan_begin_arg; + + unsigned int convert_src; + unsigned int convert_arg; + + unsigned int scan_end_src; + unsigned int scan_end_arg; + + unsigned int stop_src; + unsigned int stop_arg; + + unsigned int *chanlist; /* channel/range list */ + unsigned int chanlist_len; + + short __user *data; /* data list, size depends on subd flags */ + unsigned int data_len; +}; + +struct comedi_chaninfo { + unsigned int subdev; + unsigned int __user *maxdata_list; + unsigned int __user *flaglist; + unsigned int __user *rangelist; + unsigned int unused[4]; +}; + +struct comedi_rangeinfo { + unsigned int range_type; + void __user *range_ptr; +}; + +struct comedi_krange { + int min; /* fixed point, multiply by 1e-6 */ + int max; /* fixed point, multiply by 1e-6 */ + unsigned int flags; +}; + +struct comedi_subdinfo { + unsigned int type; + unsigned int n_chan; + unsigned int subd_flags; + unsigned int timer_type; + unsigned int len_chanlist; + unsigned int maxdata; + unsigned int flags; /* channel flags */ + unsigned int range_type; /* lookup in kernel */ + unsigned int settling_time_0; + /* see support_level enum for values */ + unsigned insn_bits_support; + unsigned int unused[8]; +}; + +struct comedi_devinfo { + unsigned int version_code; + unsigned int n_subdevs; + char driver_name[COMEDI_NAMELEN]; + char board_name[COMEDI_NAMELEN]; + int read_subdevice; + int write_subdevice; + int unused[30]; +}; + +struct comedi_devconfig { + char board_name[COMEDI_NAMELEN]; + int options[COMEDI_NDEVCONFOPTS]; +}; + +struct comedi_bufconfig { + unsigned int subdevice; + unsigned int flags; + + unsigned int maximum_size; + unsigned int size; + + unsigned int unused[4]; +}; + +struct comedi_bufinfo { + unsigned int subdevice; + unsigned int bytes_read; + + unsigned int buf_write_ptr; + unsigned int buf_read_ptr; + unsigned int buf_write_count; + unsigned int buf_read_count; + + unsigned int bytes_written; + + unsigned int unused[4]; +}; /* range stuff */ @@ -465,7 +508,7 @@ /* only relevant to kernel modules. */ #define COMEDI_CB_EOS 1 /* end of scan */ -#define COMEDI_CB_EOA 2 /* end of acquisition */ +#define COMEDI_CB_EOA 2 /* end of acquisition/output */ #define COMEDI_CB_BLOCK 4 /* data has arrived: * wakes up read() / write() */ #define COMEDI_CB_EOBUF 8 /* DEPRECATED: end of buffer */ @@ -495,302 +538,306 @@ */ - enum i8254_mode { - I8254_MODE0 = (0 << 1), /* Interrupt on terminal count */ - I8254_MODE1 = (1 << 1), /* Hardware retriggerable one-shot */ - I8254_MODE2 = (2 << 1), /* Rate generator */ - I8254_MODE3 = (3 << 1), /* Square wave mode */ - I8254_MODE4 = (4 << 1), /* Software triggered strobe */ - I8254_MODE5 = (5 << 1), /* Hardware triggered strobe - * (retriggerable) */ - I8254_BCD = 1, /* use binary-coded decimal instead of binary +enum i8254_mode { + I8254_MODE0 = (0 << 1), /* Interrupt on terminal count */ + I8254_MODE1 = (1 << 1), /* Hardware retriggerable one-shot */ + I8254_MODE2 = (2 << 1), /* Rate generator */ + I8254_MODE3 = (3 << 1), /* Square wave mode */ + I8254_MODE4 = (4 << 1), /* Software triggered strobe */ + I8254_MODE5 = (5 << 1), /* Hardware triggered strobe + * (retriggerable) */ + I8254_BCD = 1, /* use binary-coded decimal instead of binary * (pretty useless) */ - I8254_BINARY = 0 - }; - - static inline unsigned NI_USUAL_PFI_SELECT(unsigned pfi_channel) - { - if (pfi_channel < 10) - return 0x1 + pfi_channel; - else - return 0xb + pfi_channel; - } static inline unsigned NI_USUAL_RTSI_SELECT(unsigned rtsi_channel) { - if (rtsi_channel < 7) - return 0xb + rtsi_channel; - else - return 0x1b; - } + I8254_BINARY = 0 +}; + +static inline unsigned NI_USUAL_PFI_SELECT(unsigned pfi_channel) +{ + if (pfi_channel < 10) + return 0x1 + pfi_channel; + else + return 0xb + pfi_channel; +} + +static inline unsigned NI_USUAL_RTSI_SELECT(unsigned rtsi_channel) +{ + if (rtsi_channel < 7) + return 0xb + rtsi_channel; + else + return 0x1b; +} + /* mode bits for NI general-purpose counters, set with * INSN_CONFIG_SET_COUNTER_MODE */ #define NI_GPCT_COUNTING_MODE_SHIFT 16 #define NI_GPCT_INDEX_PHASE_BITSHIFT 20 #define NI_GPCT_COUNTING_DIRECTION_SHIFT 24 - enum ni_gpct_mode_bits { - NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4, - NI_GPCT_EDGE_GATE_MODE_MASK = 0x18, - NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0, - NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8, - NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10, - NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18, - NI_GPCT_STOP_MODE_MASK = 0x60, - NI_GPCT_STOP_ON_GATE_BITS = 0x00, - NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20, - NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40, - NI_GPCT_LOAD_B_SELECT_BIT = 0x80, - NI_GPCT_OUTPUT_MODE_MASK = 0x300, - NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100, - NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200, - NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300, - NI_GPCT_HARDWARE_DISARM_MASK = 0xc00, - NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000, - NI_GPCT_DISARM_AT_TC_BITS = 0x400, - NI_GPCT_DISARM_AT_GATE_BITS = 0x800, - NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00, - NI_GPCT_LOADING_ON_TC_BIT = 0x1000, - NI_GPCT_LOADING_ON_GATE_BIT = 0x4000, - NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_NORMAL_BITS = - 0x0 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS = - 0x1 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS = - 0x2 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS = - 0x3 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS = - 0x4 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS = - 0x6 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS = - 0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS = - 0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS = - 0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS = - 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_ENABLE_BIT = 0x400000, - NI_GPCT_COUNTING_DIRECTION_MASK = - 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_COUNTING_DIRECTION_DOWN_BITS = - 0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_COUNTING_DIRECTION_UP_BITS = - 0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS = - 0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS = - 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000, - NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0, - NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000, - NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000, - NI_GPCT_OR_GATE_BIT = 0x10000000, - NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000 - }; +enum ni_gpct_mode_bits { + NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4, + NI_GPCT_EDGE_GATE_MODE_MASK = 0x18, + NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0, + NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8, + NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10, + NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18, + NI_GPCT_STOP_MODE_MASK = 0x60, + NI_GPCT_STOP_ON_GATE_BITS = 0x00, + NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20, + NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40, + NI_GPCT_LOAD_B_SELECT_BIT = 0x80, + NI_GPCT_OUTPUT_MODE_MASK = 0x300, + NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100, + NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200, + NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300, + NI_GPCT_HARDWARE_DISARM_MASK = 0xc00, + NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000, + NI_GPCT_DISARM_AT_TC_BITS = 0x400, + NI_GPCT_DISARM_AT_GATE_BITS = 0x800, + NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00, + NI_GPCT_LOADING_ON_TC_BIT = 0x1000, + NI_GPCT_LOADING_ON_GATE_BIT = 0x4000, + NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_NORMAL_BITS = + 0x0 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS = + 0x1 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS = + 0x2 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS = + 0x3 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS = + 0x4 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS = + 0x6 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS = + 0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS = + 0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS = + 0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS = + 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_ENABLE_BIT = 0x400000, + NI_GPCT_COUNTING_DIRECTION_MASK = + 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_DOWN_BITS = + 0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_UP_BITS = + 0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS = + 0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS = + 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000, + NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0, + NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000, + NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000, + NI_GPCT_OR_GATE_BIT = 0x10000000, + NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000 +}; /* Bits for setting a clock source with * INSN_CONFIG_SET_CLOCK_SRC when using NI general-purpose counters. */ - enum ni_gpct_clock_source_bits { - NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f, - NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0, - NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS = 0x1, - NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS = 0x2, - NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS = 0x3, - NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS = 0x4, - NI_GPCT_NEXT_TC_CLOCK_SRC_BITS = 0x5, - /* NI 660x-specific */ - NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6, - NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7, - NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8, - NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9, - NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK = 0x30000000, - NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS = 0x0, - /* divide source by 2 */ - NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS = 0x10000000, - /* divide source by 8 */ - NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS = 0x20000000, - NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000 - }; - static inline unsigned NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(unsigned n) - { - /* NI 660x-specific */ - return 0x10 + n; - } - static inline unsigned NI_GPCT_RTSI_CLOCK_SRC_BITS(unsigned n) - { - return 0x18 + n; - } - static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n) - { - /* no pfi on NI 660x */ - return 0x20 + n; - } +enum ni_gpct_clock_source_bits { + NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f, + NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0, + NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS = 0x1, + NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS = 0x2, + NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS = 0x3, + NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS = 0x4, + NI_GPCT_NEXT_TC_CLOCK_SRC_BITS = 0x5, + /* NI 660x-specific */ + NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6, + NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7, + NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8, + NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9, + NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK = 0x30000000, + NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS = 0x0, + /* divide source by 2 */ + NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS = 0x10000000, + /* divide source by 8 */ + NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS = 0x20000000, + NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000 +}; +static inline unsigned NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(unsigned n) +{ + /* NI 660x-specific */ + return 0x10 + n; +} +static inline unsigned NI_GPCT_RTSI_CLOCK_SRC_BITS(unsigned n) +{ + return 0x18 + n; +} +static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n) +{ + /* no pfi on NI 660x */ + return 0x20 + n; +} /* Possibilities for setting a gate source with INSN_CONFIG_SET_GATE_SRC when using NI general-purpose counters. May be bitwise-or'd with CR_EDGE or CR_INVERT. */ - enum ni_gpct_gate_select { - /* m-series gates */ - NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0, - NI_GPCT_AI_START2_GATE_SELECT = 0x12, - NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13, - NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14, - NI_GPCT_AI_START1_GATE_SELECT = 0x1c, - NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d, - NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e, - NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f, - /* more gates for 660x */ - NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100, - NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101, - /* more gates for 660x "second gate" */ - NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201, - NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e, - /* m-series "second gate" sources are unknown, - * we should add them here with an offset of 0x300 when - * known. */ - NI_GPCT_DISABLED_GATE_SELECT = 0x8000, - }; - static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n) - { - return 0x102 + n; - } - static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n) - { - return NI_USUAL_RTSI_SELECT(n); - } - static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n) - { - return NI_USUAL_PFI_SELECT(n); - } - static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n) - { - return 0x202 + n; - } +enum ni_gpct_gate_select { + /* m-series gates */ + NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0, + NI_GPCT_AI_START2_GATE_SELECT = 0x12, + NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13, + NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14, + NI_GPCT_AI_START1_GATE_SELECT = 0x1c, + NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d, + NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e, + NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f, + /* more gates for 660x */ + NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100, + NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101, + /* more gates for 660x "second gate" */ + NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201, + NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e, + /* m-series "second gate" sources are unknown, + * we should add them here with an offset of 0x300 when + * known. */ + NI_GPCT_DISABLED_GATE_SELECT = 0x8000, +}; +static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n) +{ + return 0x102 + n; +} +static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n) +{ + return NI_USUAL_RTSI_SELECT(n); +} +static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n) +{ + return NI_USUAL_PFI_SELECT(n); +} +static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n) +{ + return 0x202 + n; +} /* Possibilities for setting a source with INSN_CONFIG_SET_OTHER_SRC when using NI general-purpose counters. */ - enum ni_gpct_other_index { - NI_GPCT_SOURCE_ENCODER_A, - NI_GPCT_SOURCE_ENCODER_B, - NI_GPCT_SOURCE_ENCODER_Z - }; - enum ni_gpct_other_select { - /* m-series gates */ - /* Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT */ - NI_GPCT_DISABLED_OTHER_SELECT = 0x8000, - }; - static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n) - { - return NI_USUAL_PFI_SELECT(n); - } +enum ni_gpct_other_index { + NI_GPCT_SOURCE_ENCODER_A, + NI_GPCT_SOURCE_ENCODER_B, + NI_GPCT_SOURCE_ENCODER_Z +}; +enum ni_gpct_other_select { + /* m-series gates */ + /* Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT */ + NI_GPCT_DISABLED_OTHER_SELECT = 0x8000, +}; +static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n) +{ + return NI_USUAL_PFI_SELECT(n); +} /* start sources for ni general-purpose counters for use with INSN_CONFIG_ARM */ - enum ni_gpct_arm_source { - NI_GPCT_ARM_IMMEDIATE = 0x0, - NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter - * and the adjacent paired - * counter simultaneously */ - /* NI doesn't document bits for selecting hardware arm triggers. - * If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least - * significant bits (3 bits for 660x or 5 bits for m-series) - * through to the hardware. This will at least allow someone to - * figure out what the bits do later. */ - NI_GPCT_ARM_UNKNOWN = 0x1000, - }; +enum ni_gpct_arm_source { + NI_GPCT_ARM_IMMEDIATE = 0x0, + NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter + * and the adjacent paired + * counter simultaneously */ + /* NI doesn't document bits for selecting hardware arm triggers. + * If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least + * significant bits (3 bits for 660x or 5 bits for m-series) + * through to the hardware. This will at least allow someone to + * figure out what the bits do later. */ + NI_GPCT_ARM_UNKNOWN = 0x1000, +}; /* digital filtering options for ni 660x for use with INSN_CONFIG_FILTER. */ - enum ni_gpct_filter_select { - NI_GPCT_FILTER_OFF = 0x0, - NI_GPCT_FILTER_TIMEBASE_3_SYNC = 0x1, - NI_GPCT_FILTER_100x_TIMEBASE_1 = 0x2, - NI_GPCT_FILTER_20x_TIMEBASE_1 = 0x3, - NI_GPCT_FILTER_10x_TIMEBASE_1 = 0x4, - NI_GPCT_FILTER_2x_TIMEBASE_1 = 0x5, - NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6 - }; +enum ni_gpct_filter_select { + NI_GPCT_FILTER_OFF = 0x0, + NI_GPCT_FILTER_TIMEBASE_3_SYNC = 0x1, + NI_GPCT_FILTER_100x_TIMEBASE_1 = 0x2, + NI_GPCT_FILTER_20x_TIMEBASE_1 = 0x3, + NI_GPCT_FILTER_10x_TIMEBASE_1 = 0x4, + NI_GPCT_FILTER_2x_TIMEBASE_1 = 0x5, + NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6 +}; /* PFI digital filtering options for ni m-series for use with * INSN_CONFIG_FILTER. */ - enum ni_pfi_filter_select { - NI_PFI_FILTER_OFF = 0x0, - NI_PFI_FILTER_125ns = 0x1, - NI_PFI_FILTER_6425ns = 0x2, - NI_PFI_FILTER_2550us = 0x3 - }; +enum ni_pfi_filter_select { + NI_PFI_FILTER_OFF = 0x0, + NI_PFI_FILTER_125ns = 0x1, + NI_PFI_FILTER_6425ns = 0x2, + NI_PFI_FILTER_2550us = 0x3 +}; /* master clock sources for ni mio boards and INSN_CONFIG_SET_CLOCK_SRC */ - enum ni_mio_clock_source { - NI_MIO_INTERNAL_CLOCK = 0, - NI_MIO_RTSI_CLOCK = 1, /* doesn't work for m-series, use - NI_MIO_PLL_RTSI_CLOCK() */ - /* the NI_MIO_PLL_* sources are m-series only */ - NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2, - NI_MIO_PLL_PXI10_CLOCK = 3, - NI_MIO_PLL_RTSI0_CLOCK = 4 - }; - static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel) - { - return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel; - } +enum ni_mio_clock_source { + NI_MIO_INTERNAL_CLOCK = 0, + NI_MIO_RTSI_CLOCK = 1, /* doesn't work for m-series, use + NI_MIO_PLL_RTSI_CLOCK() */ + /* the NI_MIO_PLL_* sources are m-series only */ + NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2, + NI_MIO_PLL_PXI10_CLOCK = 3, + NI_MIO_PLL_RTSI0_CLOCK = 4 +}; +static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel) +{ + return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel; +} /* Signals which can be routed to an NI RTSI pin with INSN_CONFIG_SET_ROUTING. The numbers assigned are not arbitrary, they correspond to the bits required to program the board. */ - enum ni_rtsi_routing { - NI_RTSI_OUTPUT_ADR_START1 = 0, - NI_RTSI_OUTPUT_ADR_START2 = 1, - NI_RTSI_OUTPUT_SCLKG = 2, - NI_RTSI_OUTPUT_DACUPDN = 3, - NI_RTSI_OUTPUT_DA_START1 = 4, - NI_RTSI_OUTPUT_G_SRC0 = 5, - NI_RTSI_OUTPUT_G_GATE0 = 6, - NI_RTSI_OUTPUT_RGOUT0 = 7, - NI_RTSI_OUTPUT_RTSI_BRD_0 = 8, - NI_RTSI_OUTPUT_RTSI_OSC = 12 /* pre-m-series always have RTSI - * clock on line 7 */ - }; - static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n) - { - return NI_RTSI_OUTPUT_RTSI_BRD_0 + n; - } +enum ni_rtsi_routing { + NI_RTSI_OUTPUT_ADR_START1 = 0, + NI_RTSI_OUTPUT_ADR_START2 = 1, + NI_RTSI_OUTPUT_SCLKG = 2, + NI_RTSI_OUTPUT_DACUPDN = 3, + NI_RTSI_OUTPUT_DA_START1 = 4, + NI_RTSI_OUTPUT_G_SRC0 = 5, + NI_RTSI_OUTPUT_G_GATE0 = 6, + NI_RTSI_OUTPUT_RGOUT0 = 7, + NI_RTSI_OUTPUT_RTSI_BRD_0 = 8, + NI_RTSI_OUTPUT_RTSI_OSC = 12 /* pre-m-series always have RTSI + * clock on line 7 */ +}; +static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n) +{ + return NI_RTSI_OUTPUT_RTSI_BRD_0 + n; +} /* Signals which can be routed to an NI PFI pin on an m-series board with * INSN_CONFIG_SET_ROUTING. These numbers are also returned by * INSN_CONFIG_GET_ROUTING on pre-m-series boards, even though their routing * cannot be changed. The numbers assigned are not arbitrary, they correspond * to the bits required to program the board. */ - enum ni_pfi_routing { - NI_PFI_OUTPUT_PFI_DEFAULT = 0, - NI_PFI_OUTPUT_AI_START1 = 1, - NI_PFI_OUTPUT_AI_START2 = 2, - NI_PFI_OUTPUT_AI_CONVERT = 3, - NI_PFI_OUTPUT_G_SRC1 = 4, - NI_PFI_OUTPUT_G_GATE1 = 5, - NI_PFI_OUTPUT_AO_UPDATE_N = 6, - NI_PFI_OUTPUT_AO_START1 = 7, - NI_PFI_OUTPUT_AI_START_PULSE = 8, - NI_PFI_OUTPUT_G_SRC0 = 9, - NI_PFI_OUTPUT_G_GATE0 = 10, - NI_PFI_OUTPUT_EXT_STROBE = 11, - NI_PFI_OUTPUT_AI_EXT_MUX_CLK = 12, - NI_PFI_OUTPUT_GOUT0 = 13, - NI_PFI_OUTPUT_GOUT1 = 14, - NI_PFI_OUTPUT_FREQ_OUT = 15, - NI_PFI_OUTPUT_PFI_DO = 16, - NI_PFI_OUTPUT_I_ATRIG = 17, - NI_PFI_OUTPUT_RTSI0 = 18, - NI_PFI_OUTPUT_PXI_STAR_TRIGGER_IN = 26, - NI_PFI_OUTPUT_SCXI_TRIG1 = 27, - NI_PFI_OUTPUT_DIO_CHANGE_DETECT_RTSI = 28, - NI_PFI_OUTPUT_CDI_SAMPLE = 29, - NI_PFI_OUTPUT_CDO_UPDATE = 30 - }; - static inline unsigned NI_PFI_OUTPUT_RTSI(unsigned rtsi_channel) - { - return NI_PFI_OUTPUT_RTSI0 + rtsi_channel; - } +enum ni_pfi_routing { + NI_PFI_OUTPUT_PFI_DEFAULT = 0, + NI_PFI_OUTPUT_AI_START1 = 1, + NI_PFI_OUTPUT_AI_START2 = 2, + NI_PFI_OUTPUT_AI_CONVERT = 3, + NI_PFI_OUTPUT_G_SRC1 = 4, + NI_PFI_OUTPUT_G_GATE1 = 5, + NI_PFI_OUTPUT_AO_UPDATE_N = 6, + NI_PFI_OUTPUT_AO_START1 = 7, + NI_PFI_OUTPUT_AI_START_PULSE = 8, + NI_PFI_OUTPUT_G_SRC0 = 9, + NI_PFI_OUTPUT_G_GATE0 = 10, + NI_PFI_OUTPUT_EXT_STROBE = 11, + NI_PFI_OUTPUT_AI_EXT_MUX_CLK = 12, + NI_PFI_OUTPUT_GOUT0 = 13, + NI_PFI_OUTPUT_GOUT1 = 14, + NI_PFI_OUTPUT_FREQ_OUT = 15, + NI_PFI_OUTPUT_PFI_DO = 16, + NI_PFI_OUTPUT_I_ATRIG = 17, + NI_PFI_OUTPUT_RTSI0 = 18, + NI_PFI_OUTPUT_PXI_STAR_TRIGGER_IN = 26, + NI_PFI_OUTPUT_SCXI_TRIG1 = 27, + NI_PFI_OUTPUT_DIO_CHANGE_DETECT_RTSI = 28, + NI_PFI_OUTPUT_CDI_SAMPLE = 29, + NI_PFI_OUTPUT_CDO_UPDATE = 30 +}; +static inline unsigned NI_PFI_OUTPUT_RTSI(unsigned rtsi_channel) +{ + return NI_PFI_OUTPUT_RTSI0 + rtsi_channel; +} /* Signals which can be routed to output on a NI PFI pin on a 660x board with INSN_CONFIG_SET_ROUTING. The numbers assigned are @@ -798,113 +845,135 @@ INSN_CONFIG_ARM */ to program the board. Lines 0 to 7 can only be set to NI_660X_PFI_OUTPUT_DIO. Lines 32 to 39 can only be set to NI_660X_PFI_OUTPUT_COUNTER. */ - enum ni_660x_pfi_routing { - NI_660X_PFI_OUTPUT_COUNTER = 1, /* counter */ - NI_660X_PFI_OUTPUT_DIO = 2, /* static digital output */ - }; +enum ni_660x_pfi_routing { + NI_660X_PFI_OUTPUT_COUNTER = 1, /* counter */ + NI_660X_PFI_OUTPUT_DIO = 2, /* static digital output */ +}; /* NI External Trigger lines. These values are not arbitrary, but are related * to the bits required to program the board (offset by 1 for historical * reasons). */ - static inline unsigned NI_EXT_PFI(unsigned pfi_channel) - { - return NI_USUAL_PFI_SELECT(pfi_channel) - 1; - } - static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel) - { - return NI_USUAL_RTSI_SELECT(rtsi_channel) - 1; - } +static inline unsigned NI_EXT_PFI(unsigned pfi_channel) +{ + return NI_USUAL_PFI_SELECT(pfi_channel) - 1; +} +static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel) +{ + return NI_USUAL_RTSI_SELECT(rtsi_channel) - 1; +} /* status bits for INSN_CONFIG_GET_COUNTER_STATUS */ - enum comedi_counter_status_flags { - COMEDI_COUNTER_ARMED = 0x1, - COMEDI_COUNTER_COUNTING = 0x2, - COMEDI_COUNTER_TERMINAL_COUNT = 0x4, - }; +enum comedi_counter_status_flags { + COMEDI_COUNTER_ARMED = 0x1, + COMEDI_COUNTER_COUNTING = 0x2, + COMEDI_COUNTER_TERMINAL_COUNT = 0x4, +}; /* Clock sources for CDIO subdevice on NI m-series boards. Used as the * scan_begin_arg for a comedi_command. These sources may also be bitwise-or'd * with CR_INVERT to change polarity. */ - enum ni_m_series_cdio_scan_begin_src { - NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0, - NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18, - NI_CDIO_SCAN_BEGIN_SRC_AI_CONVERT = 19, - NI_CDIO_SCAN_BEGIN_SRC_PXI_STAR_TRIGGER = 20, - NI_CDIO_SCAN_BEGIN_SRC_G0_OUT = 28, - NI_CDIO_SCAN_BEGIN_SRC_G1_OUT = 29, - NI_CDIO_SCAN_BEGIN_SRC_ANALOG_TRIGGER = 30, - NI_CDIO_SCAN_BEGIN_SRC_AO_UPDATE = 31, - NI_CDIO_SCAN_BEGIN_SRC_FREQ_OUT = 32, - NI_CDIO_SCAN_BEGIN_SRC_DIO_CHANGE_DETECT_IRQ = 33 - }; - static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel) - { - return NI_USUAL_PFI_SELECT(pfi_channel); - } - static inline unsigned - NI_CDIO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel) - { - return NI_USUAL_RTSI_SELECT(rtsi_channel); - } +enum ni_m_series_cdio_scan_begin_src { + NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0, + NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18, + NI_CDIO_SCAN_BEGIN_SRC_AI_CONVERT = 19, + NI_CDIO_SCAN_BEGIN_SRC_PXI_STAR_TRIGGER = 20, + NI_CDIO_SCAN_BEGIN_SRC_G0_OUT = 28, + NI_CDIO_SCAN_BEGIN_SRC_G1_OUT = 29, + NI_CDIO_SCAN_BEGIN_SRC_ANALOG_TRIGGER = 30, + NI_CDIO_SCAN_BEGIN_SRC_AO_UPDATE = 31, + NI_CDIO_SCAN_BEGIN_SRC_FREQ_OUT = 32, + NI_CDIO_SCAN_BEGIN_SRC_DIO_CHANGE_DETECT_IRQ = 33 +}; +static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel) +{ + return NI_USUAL_PFI_SELECT(pfi_channel); +} +static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel) +{ + return NI_USUAL_RTSI_SELECT(rtsi_channel); +} /* scan_begin_src for scan_begin_arg==TRIG_EXT with analog output command on NI * boards. These scan begin sources can also be bitwise-or'd with CR_INVERT to * change polarity. */ - static inline unsigned NI_AO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel) - { - return NI_USUAL_PFI_SELECT(pfi_channel); - } - static inline unsigned NI_AO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel) - { - return NI_USUAL_RTSI_SELECT(rtsi_channel); - } +static inline unsigned NI_AO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel) +{ + return NI_USUAL_PFI_SELECT(pfi_channel); +} +static inline unsigned NI_AO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel) +{ + return NI_USUAL_RTSI_SELECT(rtsi_channel); +} /* Bits for setting a clock source with * INSN_CONFIG_SET_CLOCK_SRC when using NI frequency output subdevice. */ - enum ni_freq_out_clock_source_bits { - NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC, /* 10 MHz */ - NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC /* 100 KHz */ - }; +enum ni_freq_out_clock_source_bits { + NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC, /* 10 MHz */ + NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC /* 100 KHz */ +}; /* Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */ - enum amplc_dio_clock_source { - AMPLC_DIO_CLK_CLKN, /* per channel external clock - input/output pin (pin is only an - input when clock source set to this - value, otherwise it is an output) */ - AMPLC_DIO_CLK_10MHZ, /* 10 MHz internal clock */ - AMPLC_DIO_CLK_1MHZ, /* 1 MHz internal clock */ - AMPLC_DIO_CLK_100KHZ, /* 100 kHz internal clock */ - AMPLC_DIO_CLK_10KHZ, /* 10 kHz internal clock */ - AMPLC_DIO_CLK_1KHZ, /* 1 kHz internal clock */ - AMPLC_DIO_CLK_OUTNM1, /* output of preceding counter channel - (for channel 0, preceding counter - channel is channel 2 on preceding - counter subdevice, for first counter - subdevice, preceding counter - subdevice is the last counter - subdevice) */ - AMPLC_DIO_CLK_EXT /* per chip external input pin */ - }; +enum amplc_dio_clock_source { + AMPLC_DIO_CLK_CLKN, /* per channel external clock + input/output pin (pin is only an + input when clock source set to this + value, otherwise it is an output) */ + AMPLC_DIO_CLK_10MHZ, /* 10 MHz internal clock */ + AMPLC_DIO_CLK_1MHZ, /* 1 MHz internal clock */ + AMPLC_DIO_CLK_100KHZ, /* 100 kHz internal clock */ + AMPLC_DIO_CLK_10KHZ, /* 10 kHz internal clock */ + AMPLC_DIO_CLK_1KHZ, /* 1 kHz internal clock */ + AMPLC_DIO_CLK_OUTNM1, /* output of preceding counter channel + (for channel 0, preceding counter + channel is channel 2 on preceding + counter subdevice, for first counter + subdevice, preceding counter + subdevice is the last counter + subdevice) */ + AMPLC_DIO_CLK_EXT, /* per chip external input pin */ + /* the following are "enhanced" clock sources for PCIe models */ + AMPLC_DIO_CLK_VCC, /* clock input HIGH */ + AMPLC_DIO_CLK_GND, /* clock input LOW */ + AMPLC_DIO_CLK_PAT_PRESENT, /* "pattern present" signal */ + AMPLC_DIO_CLK_20MHZ /* 20 MHz internal clock */ +}; + +/* Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for + * timer subdevice on some Amplicon DIO PCIe boards (amplc_dio200 driver). */ +enum amplc_dio_ts_clock_src { + AMPLC_DIO_TS_CLK_1GHZ, /* 1 ns period with 20 ns granularity */ + AMPLC_DIO_TS_CLK_1MHZ, /* 1 us period */ + AMPLC_DIO_TS_CLK_1KHZ /* 1 ms period */ +}; /* Values for setting a gate source with INSN_CONFIG_SET_GATE_SRC for * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */ - enum amplc_dio_gate_source { - AMPLC_DIO_GAT_VCC, /* internal high logic level */ - AMPLC_DIO_GAT_GND, /* internal low logic level */ - AMPLC_DIO_GAT_GATN, /* per channel external gate input */ - AMPLC_DIO_GAT_NOUTNM2, /* negated output of counter channel - minus 2 (for channels 0 or 1, - channel minus 2 is channel 1 or 2 on - the preceding counter subdevice, for - the first counter subdevice the - preceding counter subdevice is the - last counter subdevice) */ - AMPLC_DIO_GAT_RESERVED4, - AMPLC_DIO_GAT_RESERVED5, - AMPLC_DIO_GAT_RESERVED6, - AMPLC_DIO_GAT_RESERVED7 - }; +enum amplc_dio_gate_source { + AMPLC_DIO_GAT_VCC, /* internal high logic level */ + AMPLC_DIO_GAT_GND, /* internal low logic level */ + AMPLC_DIO_GAT_GATN, /* per channel external gate input */ + AMPLC_DIO_GAT_NOUTNM2, /* negated output of counter channel + minus 2 (for channels 0 or 1, + channel minus 2 is channel 1 or 2 on + the preceding counter subdevice, for + the first counter subdevice the + preceding counter subdevice is the + last counter subdevice) */ + AMPLC_DIO_GAT_RESERVED4, + AMPLC_DIO_GAT_RESERVED5, + AMPLC_DIO_GAT_RESERVED6, + AMPLC_DIO_GAT_RESERVED7, + /* the following are "enhanced" gate sources for PCIe models */ + AMPLC_DIO_GAT_NGATN = 6, /* negated per channel gate input */ + AMPLC_DIO_GAT_OUTNM2, /* non-negated output of counter + channel minus 2 */ + AMPLC_DIO_GAT_PAT_PRESENT, /* "pattern present" signal */ + AMPLC_DIO_GAT_PAT_OCCURRED, /* "pattern occurred" latched */ + AMPLC_DIO_GAT_PAT_GONE, /* "pattern gone away" latched */ + AMPLC_DIO_GAT_NPAT_PRESENT, /* negated "pattern present" */ + AMPLC_DIO_GAT_NPAT_OCCURRED, /* negated "pattern occurred" */ + AMPLC_DIO_GAT_NPAT_GONE /* negated "pattern gone away" */ +}; #endif /* _COMEDI_H */ diff --git a/drivers/staging/comedi/comedi_buf.c b/drivers/staging/comedi/comedi_buf.c new file mode 100644 index 00000000000..df4a9c4bca3 --- /dev/null +++ b/drivers/staging/comedi/comedi_buf.c @@ -0,0 +1,511 @@ +/* + * comedi_buf.c + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-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. + */ + +#include <linux/vmalloc.h> +#include <linux/slab.h> + +#include "comedidev.h" +#include "comedi_internal.h" + +#ifdef PAGE_KERNEL_NOCACHE +#define COMEDI_PAGE_PROTECTION PAGE_KERNEL_NOCACHE +#else +#define COMEDI_PAGE_PROTECTION PAGE_KERNEL +#endif + +static void comedi_buf_map_kref_release(struct kref *kref) +{ + struct comedi_buf_map *bm = + container_of(kref, struct comedi_buf_map, refcount); + struct comedi_buf_page *buf; + unsigned int i; + + if (bm->page_list) { + for (i = 0; i < bm->n_pages; i++) { + buf = &bm->page_list[i]; + clear_bit(PG_reserved, + &(virt_to_page(buf->virt_addr)->flags)); + if (bm->dma_dir != DMA_NONE) { +#ifdef CONFIG_HAS_DMA + dma_free_coherent(bm->dma_hw_dev, + PAGE_SIZE, + buf->virt_addr, + buf->dma_addr); +#endif + } else { + free_page((unsigned long)buf->virt_addr); + } + } + vfree(bm->page_list); + } + if (bm->dma_dir != DMA_NONE) + put_device(bm->dma_hw_dev); + kfree(bm); +} + +static void __comedi_buf_free(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + struct comedi_buf_map *bm; + unsigned long flags; + + if (async->prealloc_buf) { + vunmap(async->prealloc_buf); + async->prealloc_buf = NULL; + async->prealloc_bufsz = 0; + } + + spin_lock_irqsave(&s->spin_lock, flags); + bm = async->buf_map; + async->buf_map = NULL; + spin_unlock_irqrestore(&s->spin_lock, flags); + comedi_buf_map_put(bm); +} + +static void __comedi_buf_alloc(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned n_pages) +{ + struct comedi_async *async = s->async; + struct page **pages = NULL; + struct comedi_buf_map *bm; + struct comedi_buf_page *buf; + unsigned long flags; + unsigned i; + + if (!IS_ENABLED(CONFIG_HAS_DMA) && s->async_dma_dir != DMA_NONE) { + dev_err(dev->class_dev, + "dma buffer allocation not supported\n"); + return; + } + + bm = kzalloc(sizeof(*async->buf_map), GFP_KERNEL); + if (!bm) + return; + + kref_init(&bm->refcount); + spin_lock_irqsave(&s->spin_lock, flags); + async->buf_map = bm; + spin_unlock_irqrestore(&s->spin_lock, flags); + bm->dma_dir = s->async_dma_dir; + if (bm->dma_dir != DMA_NONE) + /* Need ref to hardware device to free buffer later. */ + bm->dma_hw_dev = get_device(dev->hw_dev); + + bm->page_list = vzalloc(sizeof(*buf) * n_pages); + if (bm->page_list) + pages = vmalloc(sizeof(struct page *) * n_pages); + + if (!pages) + return; + + for (i = 0; i < n_pages; i++) { + buf = &bm->page_list[i]; + if (bm->dma_dir != DMA_NONE) +#ifdef CONFIG_HAS_DMA + buf->virt_addr = dma_alloc_coherent(bm->dma_hw_dev, + PAGE_SIZE, + &buf->dma_addr, + GFP_KERNEL | + __GFP_COMP); +#else + break; +#endif + else + buf->virt_addr = (void *)get_zeroed_page(GFP_KERNEL); + if (!buf->virt_addr) + break; + + set_bit(PG_reserved, &(virt_to_page(buf->virt_addr)->flags)); + + pages[i] = virt_to_page(buf->virt_addr); + } + spin_lock_irqsave(&s->spin_lock, flags); + bm->n_pages = i; + spin_unlock_irqrestore(&s->spin_lock, flags); + + /* vmap the prealloc_buf if all the pages were allocated */ + if (i == n_pages) + async->prealloc_buf = vmap(pages, n_pages, VM_MAP, + COMEDI_PAGE_PROTECTION); + + vfree(pages); +} + +void comedi_buf_map_get(struct comedi_buf_map *bm) +{ + if (bm) + kref_get(&bm->refcount); +} + +int comedi_buf_map_put(struct comedi_buf_map *bm) +{ + if (bm) + return kref_put(&bm->refcount, comedi_buf_map_kref_release); + return 1; +} + +/* returns s->async->buf_map and increments its kref refcount */ +struct comedi_buf_map * +comedi_buf_map_from_subdev_get(struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + struct comedi_buf_map *bm = NULL; + unsigned long flags; + + if (!async) + return NULL; + + spin_lock_irqsave(&s->spin_lock, flags); + bm = async->buf_map; + /* only want it if buffer pages allocated */ + if (bm && bm->n_pages) + comedi_buf_map_get(bm); + else + bm = NULL; + spin_unlock_irqrestore(&s->spin_lock, flags); + + return bm; +} + +bool comedi_buf_is_mmapped(struct comedi_subdevice *s) +{ + struct comedi_buf_map *bm = s->async->buf_map; + + return bm && (atomic_read(&bm->refcount.refcount) > 1); +} + +int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned long new_size) +{ + struct comedi_async *async = s->async; + + /* Round up new_size to multiple of PAGE_SIZE */ + new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; + + /* if no change is required, do nothing */ + if (async->prealloc_buf && async->prealloc_bufsz == new_size) + return 0; + + /* deallocate old buffer */ + __comedi_buf_free(dev, s); + + /* allocate new buffer */ + if (new_size) { + unsigned n_pages = new_size >> PAGE_SHIFT; + + __comedi_buf_alloc(dev, s, n_pages); + + if (!async->prealloc_buf) { + /* allocation failed */ + __comedi_buf_free(dev, s); + return -ENOMEM; + } + } + async->prealloc_bufsz = new_size; + + return 0; +} + +void comedi_buf_reset(struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + + async->buf_write_alloc_count = 0; + async->buf_write_count = 0; + async->buf_read_alloc_count = 0; + async->buf_read_count = 0; + + async->buf_write_ptr = 0; + async->buf_read_ptr = 0; + + async->cur_chan = 0; + async->scan_progress = 0; + async->munge_chan = 0; + async->munge_count = 0; + async->munge_ptr = 0; + + async->events = 0; +} + +static unsigned int comedi_buf_write_n_available(struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; + + return free_end - async->buf_write_alloc_count; +} + +static unsigned int __comedi_buf_write_alloc(struct comedi_subdevice *s, + unsigned int nbytes, + int strict) +{ + struct comedi_async *async = s->async; + unsigned int available = comedi_buf_write_n_available(s); + + if (nbytes > available) + nbytes = strict ? 0 : available; + + async->buf_write_alloc_count += nbytes; + + /* + * ensure the async buffer 'counts' are read and updated + * before we write data to the write-alloc'ed buffer space + */ + smp_mb(); + + return nbytes; +} + +/* allocates chunk for the writer from free buffer space */ +unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, + unsigned int nbytes) +{ + return __comedi_buf_write_alloc(s, nbytes, 0); +} +EXPORT_SYMBOL_GPL(comedi_buf_write_alloc); + +/* + * munging is applied to data by core as it passes between user + * and kernel space + */ +static unsigned int comedi_buf_munge(struct comedi_subdevice *s, + unsigned int num_bytes) +{ + struct comedi_async *async = s->async; + unsigned int count = 0; + const unsigned num_sample_bytes = bytes_per_sample(s); + + if (!s->munge || (async->cmd.flags & CMDF_RAWDATA)) { + async->munge_count += num_bytes; + count = num_bytes; + } else { + /* don't munge partial samples */ + num_bytes -= num_bytes % num_sample_bytes; + while (count < num_bytes) { + int block_size = num_bytes - count; + unsigned int buf_end; + + buf_end = async->prealloc_bufsz - async->munge_ptr; + if (block_size > buf_end) + block_size = buf_end; + + s->munge(s->device, s, + async->prealloc_buf + async->munge_ptr, + block_size, async->munge_chan); + + /* + * ensure data is munged in buffer before the + * async buffer munge_count is incremented + */ + smp_wmb(); + + async->munge_chan += block_size / num_sample_bytes; + async->munge_chan %= async->cmd.chanlist_len; + async->munge_count += block_size; + async->munge_ptr += block_size; + async->munge_ptr %= async->prealloc_bufsz; + count += block_size; + } + } + + return count; +} + +unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + + return async->buf_write_alloc_count - async->buf_write_count; +} + +/* transfers a chunk from writer to filled buffer space */ +unsigned int comedi_buf_write_free(struct comedi_subdevice *s, + unsigned int nbytes) +{ + struct comedi_async *async = s->async; + unsigned int allocated = comedi_buf_write_n_allocated(s); + + if (nbytes > allocated) + nbytes = allocated; + + async->buf_write_count += nbytes; + async->buf_write_ptr += nbytes; + comedi_buf_munge(s, async->buf_write_count - async->munge_count); + if (async->buf_write_ptr >= async->prealloc_bufsz) + async->buf_write_ptr %= async->prealloc_bufsz; + + return nbytes; +} +EXPORT_SYMBOL_GPL(comedi_buf_write_free); + +unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + unsigned num_bytes; + + if (!async) + return 0; + + num_bytes = async->munge_count - async->buf_read_count; + + /* + * ensure the async buffer 'counts' are read before we + * attempt to read data from the buffer + */ + smp_rmb(); + + return num_bytes; +} +EXPORT_SYMBOL_GPL(comedi_buf_read_n_available); + +/* allocates a chunk for the reader from filled (and munged) buffer space */ +unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, + unsigned int nbytes) +{ + struct comedi_async *async = s->async; + unsigned int available; + + available = async->munge_count - async->buf_read_alloc_count; + if (nbytes > available) + nbytes = available; + + async->buf_read_alloc_count += nbytes; + + /* + * ensure the async buffer 'counts' are read before we + * attempt to read data from the read-alloc'ed buffer space + */ + smp_rmb(); + + return nbytes; +} +EXPORT_SYMBOL_GPL(comedi_buf_read_alloc); + +static unsigned int comedi_buf_read_n_allocated(struct comedi_async *async) +{ + return async->buf_read_alloc_count - async->buf_read_count; +} + +/* transfers control of a chunk from reader to free buffer space */ +unsigned int comedi_buf_read_free(struct comedi_subdevice *s, + unsigned int nbytes) +{ + struct comedi_async *async = s->async; + unsigned int allocated; + + /* + * ensure data has been read out of buffer before + * the async read count is incremented + */ + smp_mb(); + + allocated = comedi_buf_read_n_allocated(async); + if (nbytes > allocated) + nbytes = allocated; + + async->buf_read_count += nbytes; + async->buf_read_ptr += nbytes; + async->buf_read_ptr %= async->prealloc_bufsz; + return nbytes; +} +EXPORT_SYMBOL_GPL(comedi_buf_read_free); + +int comedi_buf_put(struct comedi_subdevice *s, unsigned short x) +{ + struct comedi_async *async = s->async; + unsigned int n = __comedi_buf_write_alloc(s, sizeof(short), 1); + + if (n < sizeof(short)) { + async->events |= COMEDI_CB_ERROR; + return 0; + } + *(unsigned short *)(async->prealloc_buf + async->buf_write_ptr) = x; + comedi_buf_write_free(s, sizeof(short)); + return 1; +} +EXPORT_SYMBOL_GPL(comedi_buf_put); + +int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x) +{ + struct comedi_async *async = s->async; + unsigned int n = comedi_buf_read_n_available(s); + + if (n < sizeof(short)) + return 0; + comedi_buf_read_alloc(s, sizeof(short)); + *x = *(unsigned short *)(async->prealloc_buf + async->buf_read_ptr); + comedi_buf_read_free(s, sizeof(short)); + return 1; +} +EXPORT_SYMBOL_GPL(comedi_buf_get); + +void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset, + const void *data, unsigned int num_bytes) +{ + struct comedi_async *async = s->async; + unsigned int write_ptr = async->buf_write_ptr + offset; + + if (write_ptr >= async->prealloc_bufsz) + write_ptr %= async->prealloc_bufsz; + + while (num_bytes) { + unsigned int block_size; + + if (write_ptr + num_bytes > async->prealloc_bufsz) + block_size = async->prealloc_bufsz - write_ptr; + else + block_size = num_bytes; + + memcpy(async->prealloc_buf + write_ptr, data, block_size); + + data += block_size; + num_bytes -= block_size; + + write_ptr = 0; + } +} +EXPORT_SYMBOL_GPL(comedi_buf_memcpy_to); + +void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset, + void *dest, unsigned int nbytes) +{ + void *src; + struct comedi_async *async = s->async; + unsigned int read_ptr = async->buf_read_ptr + offset; + + if (read_ptr >= async->prealloc_bufsz) + read_ptr %= async->prealloc_bufsz; + + while (nbytes) { + unsigned int block_size; + + src = async->prealloc_buf + read_ptr; + + if (nbytes >= async->prealloc_bufsz - read_ptr) + block_size = async->prealloc_bufsz - read_ptr; + else + block_size = nbytes; + + memcpy(dest, src, block_size); + nbytes -= block_size; + dest += block_size; + read_ptr = 0; + } +} +EXPORT_SYMBOL_GPL(comedi_buf_memcpy_from); diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c index 41a7a62ba49..1e9da405d83 100644 --- a/drivers/staging/comedi/comedi_compat32.c +++ b/drivers/staging/comedi/comedi_compat32.c @@ -17,20 +17,14 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#define __NO_VERSION__ #include <linux/uaccess.h> +#include <linux/compat.h> +#include <linux/fs.h> #include "comedi.h" #include "comedi_compat32.h" -#ifdef CONFIG_COMPAT - #define COMEDI32_CHANINFO _IOR(CIO, 3, struct comedi32_chaninfo_struct) #define COMEDI32_RANGEINFO _IOR(CIO, 8, struct comedi32_rangeinfo_struct) /* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR. @@ -92,9 +86,6 @@ struct comedi32_insnlist_struct { static int translated_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - if (!file->f_op) - return -ENOTTY; - if (file->f_op->unlocked_ioctl) return file->f_op->unlocked_ioctl(file, cmd, arg); @@ -459,5 +450,3 @@ long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return raw_ioctl(file, cmd, arg); } - -#endif /* CONFIG_COMPAT */ diff --git a/drivers/staging/comedi/comedi_compat32.h b/drivers/staging/comedi/comedi_compat32.h index 0340a8949c6..28e3c305903 100644 --- a/drivers/staging/comedi/comedi_compat32.h +++ b/drivers/staging/comedi/comedi_compat32.h @@ -17,27 +17,20 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDI_COMPAT32_H #define _COMEDI_COMPAT32_H -#include <linux/compat.h> -#include <linux/fs.h> - #ifdef CONFIG_COMPAT +struct file; extern long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); #else /* CONFIG_COMPAT */ -#define comedi_compat_ioctl 0 /* NULL */ +#define comedi_compat_ioctl NULL #endif /* CONFIG_COMPAT */ diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index e7e72b8d8cd..9d99fb3c18a 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -14,17 +14,8 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#undef DEBUG - -#define __NO_VERSION__ -#include "comedi_fops.h" #include "comedi_compat32.h" #include <linux/module.h> @@ -33,7 +24,6 @@ #include <linux/sched.h> #include <linux/fcntl.h> #include <linux/delay.h> -#include <linux/ioport.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/kmod.h> @@ -49,165 +39,607 @@ #include <linux/io.h> #include <linux/uaccess.h> -#include "internal.h" +#include "comedi_internal.h" -MODULE_AUTHOR("http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi core module"); -MODULE_LICENSE("GPL"); +#define COMEDI_NUM_MINORS 0x100 +#define COMEDI_NUM_SUBDEVICE_MINORS \ + (COMEDI_NUM_MINORS - COMEDI_NUM_BOARD_MINORS) -#ifdef CONFIG_COMEDI_DEBUG -int comedi_debug; -EXPORT_SYMBOL(comedi_debug); -module_param(comedi_debug, int, 0644); -#endif +static int comedi_num_legacy_minors; +module_param(comedi_num_legacy_minors, int, S_IRUGO); +MODULE_PARM_DESC(comedi_num_legacy_minors, + "number of comedi minor devices to reserve for non-auto-configured devices (default 0)" + ); + +unsigned int comedi_default_buf_size_kb = CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB; +module_param(comedi_default_buf_size_kb, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(comedi_default_buf_size_kb, + "default asynchronous buffer size in KiB (default " + __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_SIZE_KB) ")"); + +unsigned int comedi_default_buf_maxsize_kb + = CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB; +module_param(comedi_default_buf_maxsize_kb, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(comedi_default_buf_maxsize_kb, + "default maximum size of asynchronous buffer in KiB (default " + __MODULE_STRING(CONFIG_COMEDI_DEFAULT_BUF_MAXSIZE_KB) ")"); + +static DEFINE_MUTEX(comedi_board_minor_table_lock); +static struct comedi_device +*comedi_board_minor_table[COMEDI_NUM_BOARD_MINORS]; + +static DEFINE_MUTEX(comedi_subdevice_minor_table_lock); +/* Note: indexed by minor - COMEDI_NUM_BOARD_MINORS. */ +static struct comedi_subdevice +*comedi_subdevice_minor_table[COMEDI_NUM_SUBDEVICE_MINORS]; + +static struct class *comedi_class; +static struct cdev comedi_cdev; -int comedi_autoconfig = 1; -module_param(comedi_autoconfig, bool, 0444); +static void comedi_device_init(struct comedi_device *dev) +{ + kref_init(&dev->refcount); + spin_lock_init(&dev->spinlock); + mutex_init(&dev->mutex); + init_rwsem(&dev->attach_lock); + dev->minor = -1; +} -static int comedi_num_legacy_minors; -module_param(comedi_num_legacy_minors, int, 0444); +static void comedi_dev_kref_release(struct kref *kref) +{ + struct comedi_device *dev = + container_of(kref, struct comedi_device, refcount); -static DEFINE_SPINLOCK(comedi_file_info_table_lock); -static struct comedi_device_file_info -*comedi_file_info_table[COMEDI_NUM_MINORS]; + mutex_destroy(&dev->mutex); + put_device(dev->class_dev); + kfree(dev); +} -static int do_devconfig_ioctl(struct comedi_device *dev, - struct comedi_devconfig __user *arg); -static int do_bufconfig_ioctl(struct comedi_device *dev, - struct comedi_bufconfig __user *arg); -static int do_devinfo_ioctl(struct comedi_device *dev, - struct comedi_devinfo __user *arg, - struct file *file); -static int do_subdinfo_ioctl(struct comedi_device *dev, - struct comedi_subdinfo __user *arg, void *file); -static int do_chaninfo_ioctl(struct comedi_device *dev, - struct comedi_chaninfo __user *arg); -static int do_bufinfo_ioctl(struct comedi_device *dev, - struct comedi_bufinfo __user *arg, void *file); -static int do_cmd_ioctl(struct comedi_device *dev, - struct comedi_cmd __user *arg, void *file); -static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, - void *file); -static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, - void *file); -static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, - void *file); -static int do_cmdtest_ioctl(struct comedi_device *dev, - struct comedi_cmd __user *arg, void *file); -static int do_insnlist_ioctl(struct comedi_device *dev, - struct comedi_insnlist __user *arg, void *file); -static int do_insn_ioctl(struct comedi_device *dev, - struct comedi_insn __user *arg, void *file); -static int do_poll_ioctl(struct comedi_device *dev, unsigned int subd, - void *file); +int comedi_dev_put(struct comedi_device *dev) +{ + if (dev) + return kref_put(&dev->refcount, comedi_dev_kref_release); + return 1; +} +EXPORT_SYMBOL_GPL(comedi_dev_put); + +static struct comedi_device *comedi_dev_get(struct comedi_device *dev) +{ + if (dev) + kref_get(&dev->refcount); + return dev; +} + +static void comedi_device_cleanup(struct comedi_device *dev) +{ + struct module *driver_module = NULL; + + if (dev == NULL) + return; + mutex_lock(&dev->mutex); + if (dev->attached) + driver_module = dev->driver->module; + comedi_device_detach(dev); + if (driver_module && dev->use_count) + module_put(driver_module); + mutex_unlock(&dev->mutex); +} + +static bool comedi_clear_board_dev(struct comedi_device *dev) +{ + unsigned int i = dev->minor; + bool cleared = false; + + mutex_lock(&comedi_board_minor_table_lock); + if (dev == comedi_board_minor_table[i]) { + comedi_board_minor_table[i] = NULL; + cleared = true; + } + mutex_unlock(&comedi_board_minor_table_lock); + return cleared; +} + +static struct comedi_device *comedi_clear_board_minor(unsigned minor) +{ + struct comedi_device *dev; + + mutex_lock(&comedi_board_minor_table_lock); + dev = comedi_board_minor_table[minor]; + comedi_board_minor_table[minor] = NULL; + mutex_unlock(&comedi_board_minor_table_lock); + return dev; +} + +static void comedi_free_board_dev(struct comedi_device *dev) +{ + if (dev) { + comedi_device_cleanup(dev); + if (dev->class_dev) { + device_destroy(comedi_class, + MKDEV(COMEDI_MAJOR, dev->minor)); + } + comedi_dev_put(dev); + } +} + +static struct comedi_subdevice +*comedi_subdevice_from_minor(const struct comedi_device *dev, unsigned minor) +{ + struct comedi_subdevice *s; + unsigned int i = minor - COMEDI_NUM_BOARD_MINORS; + + BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS); + mutex_lock(&comedi_subdevice_minor_table_lock); + s = comedi_subdevice_minor_table[i]; + if (s && s->device != dev) + s = NULL; + mutex_unlock(&comedi_subdevice_minor_table_lock); + return s; +} + +static struct comedi_device *comedi_dev_get_from_board_minor(unsigned minor) +{ + struct comedi_device *dev; + + BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); + mutex_lock(&comedi_board_minor_table_lock); + dev = comedi_dev_get(comedi_board_minor_table[minor]); + mutex_unlock(&comedi_board_minor_table_lock); + return dev; +} + +static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor) +{ + struct comedi_device *dev; + struct comedi_subdevice *s; + unsigned int i = minor - COMEDI_NUM_BOARD_MINORS; + + BUG_ON(i >= COMEDI_NUM_SUBDEVICE_MINORS); + mutex_lock(&comedi_subdevice_minor_table_lock); + s = comedi_subdevice_minor_table[i]; + dev = comedi_dev_get(s ? s->device : NULL); + mutex_unlock(&comedi_subdevice_minor_table_lock); + return dev; +} + +struct comedi_device *comedi_dev_get_from_minor(unsigned minor) +{ + if (minor < COMEDI_NUM_BOARD_MINORS) + return comedi_dev_get_from_board_minor(minor); + else + return comedi_dev_get_from_subdevice_minor(minor); +} +EXPORT_SYMBOL_GPL(comedi_dev_get_from_minor); + +static struct comedi_subdevice * +comedi_read_subdevice(const struct comedi_device *dev, unsigned int minor) +{ + struct comedi_subdevice *s; -extern void do_become_nonbusy(struct comedi_device *dev, - struct comedi_subdevice *s); -static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s); + if (minor >= COMEDI_NUM_BOARD_MINORS) { + s = comedi_subdevice_from_minor(dev, minor); + if (s == NULL || (s->subdev_flags & SDF_CMD_READ)) + return s; + } + return dev->read_subdev; +} + +static struct comedi_subdevice * +comedi_write_subdevice(const struct comedi_device *dev, unsigned int minor) +{ + struct comedi_subdevice *s; -static int comedi_fasync(int fd, struct file *file, int on); + if (minor >= COMEDI_NUM_BOARD_MINORS) { + s = comedi_subdevice_from_minor(dev, minor); + if (s == NULL || (s->subdev_flags & SDF_CMD_WRITE)) + return s; + } + return dev->write_subdev; +} -static int is_device_busy(struct comedi_device *dev); static int resize_async_buffer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_async *async, unsigned new_size); + struct comedi_subdevice *s, unsigned new_size) +{ + struct comedi_async *async = s->async; + int retval; -/* declarations for sysfs attribute files */ -static struct device_attribute dev_attr_max_read_buffer_kb; -static struct device_attribute dev_attr_read_buffer_kb; -static struct device_attribute dev_attr_max_write_buffer_kb; -static struct device_attribute dev_attr_write_buffer_kb; + if (new_size > async->max_bufsize) + return -EPERM; -static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) + if (s->busy) { + dev_dbg(dev->class_dev, + "subdevice is busy, cannot resize buffer\n"); + return -EBUSY; + } + if (comedi_buf_is_mmapped(s)) { + dev_dbg(dev->class_dev, + "subdevice is mmapped, cannot resize buffer\n"); + return -EBUSY; + } + + /* make sure buffer is an integral number of pages + * (we round up) */ + new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; + + retval = comedi_buf_alloc(dev, s, new_size); + if (retval < 0) + return retval; + + if (s->buf_change) { + retval = s->buf_change(dev, s, new_size); + if (retval < 0) + return retval; + } + + dev_dbg(dev->class_dev, "subd %d buffer resized to %i bytes\n", + s->index, async->prealloc_bufsz); + return 0; +} + +/* sysfs attribute files */ + +static ssize_t max_read_buffer_kb_show(struct device *csdev, + struct device_attribute *attr, char *buf) { - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); + unsigned int minor = MINOR(csdev->devt); struct comedi_device *dev; - int rc; + struct comedi_subdevice *s; + unsigned int size = 0; - if (dev_file_info == NULL || dev_file_info->device == NULL) + dev = comedi_dev_get_from_minor(minor); + if (!dev) return -ENODEV; - dev = dev_file_info->device; mutex_lock(&dev->mutex); + s = comedi_read_subdevice(dev, minor); + if (s && (s->subdev_flags & SDF_CMD_READ) && s->async) + size = s->async->max_bufsize / 1024; + mutex_unlock(&dev->mutex); - /* Device config is special, because it must work on - * an unconfigured device. */ - if (cmd == COMEDI_DEVCONFIG) { - rc = do_devconfig_ioctl(dev, - (struct comedi_devconfig __user *)arg); - goto done; + comedi_dev_put(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", size); +} + +static ssize_t max_read_buffer_kb_store(struct device *csdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int minor = MINOR(csdev->devt); + struct comedi_device *dev; + struct comedi_subdevice *s; + unsigned int size; + int err; + + err = kstrtouint(buf, 10, &size); + if (err) + return err; + if (size > (UINT_MAX / 1024)) + return -EINVAL; + size *= 1024; + + dev = comedi_dev_get_from_minor(minor); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->mutex); + s = comedi_read_subdevice(dev, minor); + if (s && (s->subdev_flags & SDF_CMD_READ) && s->async) + s->async->max_bufsize = size; + else + err = -EINVAL; + mutex_unlock(&dev->mutex); + + comedi_dev_put(dev); + return err ? err : count; +} +static DEVICE_ATTR_RW(max_read_buffer_kb); + +static ssize_t read_buffer_kb_show(struct device *csdev, + struct device_attribute *attr, char *buf) +{ + unsigned int minor = MINOR(csdev->devt); + struct comedi_device *dev; + struct comedi_subdevice *s; + unsigned int size = 0; + + dev = comedi_dev_get_from_minor(minor); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->mutex); + s = comedi_read_subdevice(dev, minor); + if (s && (s->subdev_flags & SDF_CMD_READ) && s->async) + size = s->async->prealloc_bufsz / 1024; + mutex_unlock(&dev->mutex); + + comedi_dev_put(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", size); +} + +static ssize_t read_buffer_kb_store(struct device *csdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int minor = MINOR(csdev->devt); + struct comedi_device *dev; + struct comedi_subdevice *s; + unsigned int size; + int err; + + err = kstrtouint(buf, 10, &size); + if (err) + return err; + if (size > (UINT_MAX / 1024)) + return -EINVAL; + size *= 1024; + + dev = comedi_dev_get_from_minor(minor); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->mutex); + s = comedi_read_subdevice(dev, minor); + if (s && (s->subdev_flags & SDF_CMD_READ) && s->async) + err = resize_async_buffer(dev, s, size); + else + err = -EINVAL; + mutex_unlock(&dev->mutex); + + comedi_dev_put(dev); + return err ? err : count; +} +static DEVICE_ATTR_RW(read_buffer_kb); + +static ssize_t max_write_buffer_kb_show(struct device *csdev, + struct device_attribute *attr, + char *buf) +{ + unsigned int minor = MINOR(csdev->devt); + struct comedi_device *dev; + struct comedi_subdevice *s; + unsigned int size = 0; + + dev = comedi_dev_get_from_minor(minor); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->mutex); + s = comedi_write_subdevice(dev, minor); + if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async) + size = s->async->max_bufsize / 1024; + mutex_unlock(&dev->mutex); + + comedi_dev_put(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", size); +} + +static ssize_t max_write_buffer_kb_store(struct device *csdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int minor = MINOR(csdev->devt); + struct comedi_device *dev; + struct comedi_subdevice *s; + unsigned int size; + int err; + + err = kstrtouint(buf, 10, &size); + if (err) + return err; + if (size > (UINT_MAX / 1024)) + return -EINVAL; + size *= 1024; + + dev = comedi_dev_get_from_minor(minor); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->mutex); + s = comedi_write_subdevice(dev, minor); + if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async) + s->async->max_bufsize = size; + else + err = -EINVAL; + mutex_unlock(&dev->mutex); + + comedi_dev_put(dev); + return err ? err : count; +} +static DEVICE_ATTR_RW(max_write_buffer_kb); + +static ssize_t write_buffer_kb_show(struct device *csdev, + struct device_attribute *attr, char *buf) +{ + unsigned int minor = MINOR(csdev->devt); + struct comedi_device *dev; + struct comedi_subdevice *s; + unsigned int size = 0; + + dev = comedi_dev_get_from_minor(minor); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->mutex); + s = comedi_write_subdevice(dev, minor); + if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async) + size = s->async->prealloc_bufsz / 1024; + mutex_unlock(&dev->mutex); + + comedi_dev_put(dev); + return snprintf(buf, PAGE_SIZE, "%u\n", size); +} + +static ssize_t write_buffer_kb_store(struct device *csdev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned int minor = MINOR(csdev->devt); + struct comedi_device *dev; + struct comedi_subdevice *s; + unsigned int size; + int err; + + err = kstrtouint(buf, 10, &size); + if (err) + return err; + if (size > (UINT_MAX / 1024)) + return -EINVAL; + size *= 1024; + + dev = comedi_dev_get_from_minor(minor); + if (!dev) + return -ENODEV; + + mutex_lock(&dev->mutex); + s = comedi_write_subdevice(dev, minor); + if (s && (s->subdev_flags & SDF_CMD_WRITE) && s->async) + err = resize_async_buffer(dev, s, size); + else + err = -EINVAL; + mutex_unlock(&dev->mutex); + + comedi_dev_put(dev); + return err ? err : count; +} +static DEVICE_ATTR_RW(write_buffer_kb); + +static struct attribute *comedi_dev_attrs[] = { + &dev_attr_max_read_buffer_kb.attr, + &dev_attr_read_buffer_kb.attr, + &dev_attr_max_write_buffer_kb.attr, + &dev_attr_write_buffer_kb.attr, + NULL, +}; +ATTRIBUTE_GROUPS(comedi_dev); + +static void comedi_set_subdevice_runflags(struct comedi_subdevice *s, + unsigned mask, unsigned bits) +{ + unsigned long flags; + + spin_lock_irqsave(&s->spin_lock, flags); + s->runflags &= ~mask; + s->runflags |= (bits & mask); + spin_unlock_irqrestore(&s->spin_lock, flags); +} + +static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) +{ + unsigned long flags; + unsigned runflags; + + spin_lock_irqsave(&s->spin_lock, flags); + runflags = s->runflags; + spin_unlock_irqrestore(&s->spin_lock, flags); + return runflags; +} + +bool comedi_is_subdevice_running(struct comedi_subdevice *s) +{ + unsigned runflags = comedi_get_subdevice_runflags(s); + + return (runflags & SRF_RUNNING) ? true : false; +} +EXPORT_SYMBOL_GPL(comedi_is_subdevice_running); + +static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s) +{ + unsigned runflags = comedi_get_subdevice_runflags(s); + + return (runflags & SRF_ERROR) ? true : false; +} + +static bool comedi_is_subdevice_idle(struct comedi_subdevice *s) +{ + unsigned runflags = comedi_get_subdevice_runflags(s); + + return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true; +} + +/** + * comedi_alloc_spriv() - Allocate memory for the subdevice private data. + * @s: comedi_subdevice struct + * @size: size of the memory to allocate + * + * This also sets the subdevice runflags to allow the core to automatically + * free the private data during the detach. + */ +void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size) +{ + s->private = kzalloc(size, GFP_KERNEL); + if (s->private) + s->runflags |= SRF_FREE_SPRIV; + return s->private; +} +EXPORT_SYMBOL_GPL(comedi_alloc_spriv); + +/* + This function restores a subdevice to an idle state. + */ +static void do_become_nonbusy(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_async *async = s->async; + + comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); + if (async) { + comedi_buf_reset(s); + async->inttrig = NULL; + kfree(async->cmd.chanlist); + async->cmd.chanlist = NULL; + s->busy = NULL; + wake_up_interruptible_all(&s->async->wait_head); + } else { + dev_err(dev->class_dev, + "BUG: (?) do_become_nonbusy called with async=NULL\n"); + s->busy = NULL; } +} - if (!dev->attached) { - DPRINTK("no driver configured on /dev/comedi%i\n", dev->minor); - rc = -ENODEV; - goto done; +static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +{ + int ret = 0; + + if (comedi_is_subdevice_running(s) && s->cancel) + ret = s->cancel(dev, s); + + do_become_nonbusy(dev, s); + + return ret; +} + +void comedi_device_cancel_all(struct comedi_device *dev) +{ + struct comedi_subdevice *s; + int i; + + if (!dev->attached) + return; + + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + if (s->async) + do_cancel(dev, s); } +} - switch (cmd) { - case COMEDI_BUFCONFIG: - rc = do_bufconfig_ioctl(dev, - (struct comedi_bufconfig __user *)arg); - break; - case COMEDI_DEVINFO: - rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg, - file); - break; - case COMEDI_SUBDINFO: - rc = do_subdinfo_ioctl(dev, - (struct comedi_subdinfo __user *)arg, - file); - break; - case COMEDI_CHANINFO: - rc = do_chaninfo_ioctl(dev, (void __user *)arg); - break; - case COMEDI_RANGEINFO: - rc = do_rangeinfo_ioctl(dev, (void __user *)arg); - break; - case COMEDI_BUFINFO: - rc = do_bufinfo_ioctl(dev, - (struct comedi_bufinfo __user *)arg, - file); - break; - case COMEDI_LOCK: - rc = do_lock_ioctl(dev, arg, file); - break; - case COMEDI_UNLOCK: - rc = do_unlock_ioctl(dev, arg, file); - break; - case COMEDI_CANCEL: - rc = do_cancel_ioctl(dev, arg, file); - break; - case COMEDI_CMD: - rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file); - break; - case COMEDI_CMDTEST: - rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg, - file); - break; - case COMEDI_INSNLIST: - rc = do_insnlist_ioctl(dev, - (struct comedi_insnlist __user *)arg, - file); - break; - case COMEDI_INSN: - rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg, - file); - break; - case COMEDI_POLL: - rc = do_poll_ioctl(dev, arg, file); - break; - default: - rc = -ENOTTY; - break; +static int is_device_busy(struct comedi_device *dev) +{ + struct comedi_subdevice *s; + int i; + + if (!dev->attached) + return 0; + + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + if (s->busy) + return 1; + if (s->async && comedi_buf_is_mmapped(s)) + return 1; } -done: - mutex_unlock(&dev->mutex); - return rc; + return 0; } /* @@ -227,9 +659,6 @@ static int do_devconfig_ioctl(struct comedi_device *dev, struct comedi_devconfig __user *arg) { struct comedi_devconfig it; - int ret; - unsigned char *aux_data = NULL; - int aux_len; if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -239,55 +668,30 @@ static int do_devconfig_ioctl(struct comedi_device *dev, return -EBUSY; if (dev->attached) { struct module *driver_module = dev->driver->module; + comedi_device_detach(dev); module_put(driver_module); } return 0; } - if (copy_from_user(&it, arg, sizeof(struct comedi_devconfig))) + if (copy_from_user(&it, arg, sizeof(it))) return -EFAULT; it.board_name[COMEDI_NAMELEN - 1] = 0; - if (comedi_aux_data(it.options, 0) && - it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { - int bit_shift; - aux_len = it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; - if (aux_len < 0) - return -EFAULT; - - aux_data = vmalloc(aux_len); - if (!aux_data) - return -ENOMEM; - - if (copy_from_user(aux_data, - comedi_aux_data(it.options, 0), aux_len)) { - vfree(aux_data); - return -EFAULT; - } - it.options[COMEDI_DEVCONF_AUX_DATA_LO] = - (unsigned long)aux_data; - if (sizeof(void *) > sizeof(int)) { - bit_shift = sizeof(int) * 8; - it.options[COMEDI_DEVCONF_AUX_DATA_HI] = - ((unsigned long)aux_data) >> bit_shift; - } else - it.options[COMEDI_DEVCONF_AUX_DATA_HI] = 0; - } - - ret = comedi_device_attach(dev, &it); - if (ret == 0) { - if (!try_module_get(dev->driver->module)) { - comedi_device_detach(dev); - return -ENOSYS; - } + if (it.options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { + dev_warn(dev->class_dev, + "comedi_config --init_data is deprecated\n"); + return -EINVAL; } - if (aux_data) - vfree(aux_data); + if (dev->minor >= comedi_num_legacy_minors) + /* don't re-use dynamically allocated comedi devices */ + return -EBUSY; - return ret; + /* This increments the driver module count on success. */ + return comedi_device_attach(dev, &it); } /* @@ -312,17 +716,18 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, struct comedi_subdevice *s; int retval = 0; - if (copy_from_user(&bc, arg, sizeof(struct comedi_bufconfig))) + if (copy_from_user(&bc, arg, sizeof(bc))) return -EFAULT; - if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0) + if (bc.subdevice >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + bc.subdevice; + s = &dev->subdevices[bc.subdevice]; async = s->async; if (!async) { - DPRINTK("subdevice does not have async capability\n"); + dev_dbg(dev->class_dev, + "subdevice does not have async capability\n"); bc.size = 0; bc.maximum_size = 0; goto copyback; @@ -336,7 +741,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, } if (bc.size) { - retval = resize_async_buffer(dev, s, async, bc.size); + retval = resize_async_buffer(dev, s, bc.size); if (retval < 0) return retval; } @@ -345,7 +750,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, bc.maximum_size = async->max_bufsize; copyback: - if (copy_to_user(arg, &bc, sizeof(struct comedi_bufconfig))) + if (copy_to_user(arg, &bc, sizeof(bc))) return -EFAULT; return 0; @@ -369,34 +774,31 @@ static int do_devinfo_ioctl(struct comedi_device *dev, struct comedi_devinfo __user *arg, struct file *file) { + const unsigned minor = iminor(file_inode(file)); + struct comedi_subdevice *s; struct comedi_devinfo devinfo; - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_subdevice *read_subdev = - comedi_get_read_subdevice(dev_file_info); - struct comedi_subdevice *write_subdev = - comedi_get_write_subdevice(dev_file_info); memset(&devinfo, 0, sizeof(devinfo)); /* fill devinfo structure */ devinfo.version_code = COMEDI_VERSION_CODE; devinfo.n_subdevs = dev->n_subdevices; - memcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN); - memcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN); + strlcpy(devinfo.driver_name, dev->driver->driver_name, COMEDI_NAMELEN); + strlcpy(devinfo.board_name, dev->board_name, COMEDI_NAMELEN); - if (read_subdev) - devinfo.read_subdevice = read_subdev - dev->subdevices; + s = comedi_read_subdevice(dev, minor); + if (s) + devinfo.read_subdevice = s->index; else devinfo.read_subdevice = -1; - if (write_subdev) - devinfo.write_subdevice = write_subdev - dev->subdevices; + s = comedi_write_subdevice(dev, minor); + if (s) + devinfo.write_subdevice = s->index; else devinfo.write_subdevice = -1; - if (copy_to_user(arg, &devinfo, sizeof(struct comedi_devinfo))) + if (copy_to_user(arg, &devinfo, sizeof(devinfo))) return -EFAULT; return 0; @@ -423,21 +825,19 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, struct comedi_subdinfo *tmp, *us; struct comedi_subdevice *s; - tmp = - kcalloc(dev->n_subdevices, sizeof(struct comedi_subdinfo), - GFP_KERNEL); + tmp = kcalloc(dev->n_subdevices, sizeof(*tmp), GFP_KERNEL); if (!tmp) return -ENOMEM; /* fill subdinfo structs */ for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; us = tmp + i; us->type = s->type; us->n_chan = s->n_chan; us->subd_flags = s->subdev_flags; - if (comedi_get_subdevice_runflags(s) & SRF_RUNNING) + if (comedi_is_subdevice_running(s)) us->subd_flags |= SDF_RUNNING; #define TIMER_nanosec 5 /* backwards compatibility */ us->timer_type = TIMER_nanosec; @@ -449,7 +849,6 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, } else { us->range_type = 0; /* XXX */ } - us->flags = s->flags; if (s->busy) us->subd_flags |= SDF_BUSY; @@ -461,8 +860,6 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, us->subd_flags |= SDF_LOCK_OWNER; if (!s->maxdata && s->maxdata_list) us->subd_flags |= SDF_MAXDATA; - if (s->flaglist) - us->subd_flags |= SDF_FLAGS; if (s->range_table_list) us->subd_flags |= SDF_RANGETYPE; if (s->do_cmd) @@ -472,12 +869,9 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, us->insn_bits_support = COMEDI_SUPPORTED; else us->insn_bits_support = COMEDI_UNSUPPORTED; - - us->settling_time_0 = s->settling_time_0; } - ret = copy_to_user(arg, tmp, - dev->n_subdevices * sizeof(struct comedi_subdinfo)); + ret = copy_to_user(arg, tmp, dev->n_subdevices * sizeof(*tmp)); kfree(tmp); @@ -504,12 +898,12 @@ static int do_chaninfo_ioctl(struct comedi_device *dev, struct comedi_subdevice *s; struct comedi_chaninfo it; - if (copy_from_user(&it, arg, sizeof(struct comedi_chaninfo))) + if (copy_from_user(&it, arg, sizeof(it))) return -EFAULT; if (it.subdev >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + it.subdev; + s = &dev->subdevices[it.subdev]; if (it.maxdata_list) { if (s->maxdata || !s->maxdata_list) @@ -519,13 +913,8 @@ static int do_chaninfo_ioctl(struct comedi_device *dev, return -EFAULT; } - if (it.flaglist) { - if (!s->flaglist) - return -EINVAL; - if (copy_to_user(it.flaglist, s->flaglist, - s->n_chan * sizeof(unsigned int))) - return -EFAULT; - } + if (it.flaglist) + return -EINVAL; /* flaglist not supported */ if (it.rangelist) { int i; @@ -571,13 +960,13 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, struct comedi_subdevice *s; struct comedi_async *async; - if (copy_from_user(&bi, arg, sizeof(struct comedi_bufinfo))) + if (copy_from_user(&bi, arg, sizeof(bi))) return -EFAULT; - if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0) + if (bi.subdevice >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + bi.subdevice; + s = &dev->subdevices[bi.subdevice]; if (s->lock && s->lock != file) return -EACCES; @@ -585,7 +974,8 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, async = s->async; if (!async) { - DPRINTK("subdevice does not have async capability\n"); + dev_dbg(dev->class_dev, + "subdevice does not have async capability\n"); bi.buf_write_ptr = 0; bi.buf_read_ptr = 0; bi.buf_write_count = 0; @@ -603,20 +993,19 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, return -EACCES; if (bi.bytes_read && (s->subdev_flags & SDF_CMD_READ)) { - bi.bytes_read = comedi_buf_read_alloc(async, bi.bytes_read); - comedi_buf_read_free(async, bi.bytes_read); + bi.bytes_read = comedi_buf_read_alloc(s, bi.bytes_read); + comedi_buf_read_free(s, bi.bytes_read); - if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | - SRF_RUNNING)) - && async->buf_write_count == async->buf_read_count) { + if (comedi_is_subdevice_idle(s) && + async->buf_write_count == async->buf_read_count) { do_become_nonbusy(dev, s); } } if (bi.bytes_written && (s->subdev_flags & SDF_CMD_WRITE)) { bi.bytes_written = - comedi_buf_write_alloc(async, bi.bytes_written); - comedi_buf_write_free(async, bi.bytes_written); + comedi_buf_write_alloc(s, bi.bytes_written); + comedi_buf_write_free(s, bi.bytes_written); } copyback_position: @@ -626,103 +1015,12 @@ copyback_position: bi.buf_read_ptr = async->buf_read_ptr; copyback: - if (copy_to_user(arg, &bi, sizeof(struct comedi_bufinfo))) + if (copy_to_user(arg, &bi, sizeof(bi))) return -EFAULT; return 0; } -static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, - unsigned int *data, void *file); -/* - * COMEDI_INSNLIST - * synchronous instructions - * - * arg: - * pointer to sync cmd structure - * - * reads: - * sync cmd struct at arg - * instruction list - * data (for writes) - * - * writes: - * data (for reads) - */ -/* arbitrary limits */ -#define MAX_SAMPLES 256 -static int do_insnlist_ioctl(struct comedi_device *dev, - struct comedi_insnlist __user *arg, void *file) -{ - struct comedi_insnlist insnlist; - struct comedi_insn *insns = NULL; - unsigned int *data = NULL; - int i = 0; - int ret = 0; - - if (copy_from_user(&insnlist, arg, sizeof(struct comedi_insnlist))) - return -EFAULT; - - data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); - if (!data) { - DPRINTK("kmalloc failed\n"); - ret = -ENOMEM; - goto error; - } - - insns = - kmalloc(sizeof(struct comedi_insn) * insnlist.n_insns, GFP_KERNEL); - if (!insns) { - DPRINTK("kmalloc failed\n"); - ret = -ENOMEM; - goto error; - } - - if (copy_from_user(insns, insnlist.insns, - sizeof(struct comedi_insn) * insnlist.n_insns)) { - DPRINTK("copy_from_user failed\n"); - ret = -EFAULT; - goto error; - } - - for (i = 0; i < insnlist.n_insns; i++) { - if (insns[i].n > MAX_SAMPLES) { - DPRINTK("number of samples too large\n"); - ret = -EINVAL; - goto error; - } - if (insns[i].insn & INSN_MASK_WRITE) { - if (copy_from_user(data, insns[i].data, - insns[i].n * sizeof(unsigned int))) { - DPRINTK("copy_from_user failed\n"); - ret = -EFAULT; - goto error; - } - } - ret = parse_insn(dev, insns + i, data, file); - if (ret < 0) - goto error; - if (insns[i].insn & INSN_MASK_READ) { - if (copy_to_user(insns[i].data, data, - insns[i].n * sizeof(unsigned int))) { - DPRINTK("copy_to_user failed\n"); - ret = -EFAULT; - goto error; - } - } - if (need_resched()) - schedule(); - } - -error: - kfree(insns); - kfree(data); - - if (ret < 0) - return ret; - return i; -} - static int check_insn_config_length(struct comedi_insn *insn, unsigned int *data) { @@ -771,17 +1069,19 @@ static int check_insn_config_length(struct comedi_insn *insn, if (insn->n == 5) return 0; break; + case INSN_CONFIG_DIGITAL_TRIG: + if (insn->n == 6) + return 0; + break; /* by default we allow the insn since we don't have checks for * all possible cases yet */ default: - printk(KERN_WARNING - "comedi: no check for data length of config insn id " - "%i is implemented.\n" - " Add a check to %s in %s.\n" - " Assuming n=%i is correct.\n", data[0], __func__, - __FILE__, insn->n); + pr_warn("comedi: No check for data length of config insn id %i is implemented.\n", + data[0]); + pr_warn("comedi: Add a check to %s in %s.\n", + __func__, __FILE__); + pr_warn("comedi: Assuming n=%i is correct.\n", insn->n); return 0; - break; } return -EINVAL; } @@ -827,28 +1127,29 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, break; } if (insn->subdev >= dev->n_subdevices) { - DPRINTK("%d not usable subdevice\n", + dev_dbg(dev->class_dev, + "%d not usable subdevice\n", insn->subdev); ret = -EINVAL; break; } - s = dev->subdevices + insn->subdev; + s = &dev->subdevices[insn->subdev]; if (!s->async) { - DPRINTK("no async\n"); + dev_dbg(dev->class_dev, "no async\n"); ret = -EINVAL; break; } if (!s->async->inttrig) { - DPRINTK("no inttrig\n"); + dev_dbg(dev->class_dev, "no inttrig\n"); ret = -EAGAIN; break; } - ret = s->async->inttrig(dev, s, insn->data[0]); + ret = s->async->inttrig(dev, s, data[0]); if (ret >= 0) ret = 1; break; default: - DPRINTK("invalid insn\n"); + dev_dbg(dev->class_dev, "invalid insn\n"); ret = -EINVAL; break; } @@ -857,21 +1158,23 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, unsigned int maxdata; if (insn->subdev >= dev->n_subdevices) { - DPRINTK("subdevice %d out of range\n", insn->subdev); + dev_dbg(dev->class_dev, "subdevice %d out of range\n", + insn->subdev); ret = -EINVAL; goto out; } - s = dev->subdevices + insn->subdev; + s = &dev->subdevices[insn->subdev]; if (s->type == COMEDI_SUBD_UNUSED) { - DPRINTK("%d not usable subdevice\n", insn->subdev); + dev_dbg(dev->class_dev, "%d not usable subdevice\n", + insn->subdev); ret = -EIO; goto out; } /* are we locked? (ioctl lock) */ if (s->lock && s->lock != file) { - DPRINTK("device locked\n"); + dev_dbg(dev->class_dev, "device locked\n"); ret = -EACCES; goto out; } @@ -879,7 +1182,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, ret = comedi_check_chanlist(s, 1, &insn->chanspec); if (ret < 0) { ret = -EINVAL; - DPRINTK("bad chanspec\n"); + dev_dbg(dev->class_dev, "bad chanspec\n"); goto out; } @@ -892,6 +1195,11 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, switch (insn->insn) { case INSN_READ: ret = s->insn_read(dev, s, insn, data); + if (ret == -ETIMEDOUT) { + dev_dbg(dev->class_dev, + "subdevice %d read instruction timed out\n", + s->index); + } break; case INSN_WRITE: maxdata = s->maxdata_list @@ -900,12 +1208,19 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, for (i = 0; i < insn->n; ++i) { if (data[i] > maxdata) { ret = -EINVAL; - DPRINTK("bad data value(s)\n"); + dev_dbg(dev->class_dev, + "bad data value(s)\n"); break; } } - if (ret == 0) + if (ret == 0) { ret = s->insn_write(dev, s, insn, data); + if (ret == -ETIMEDOUT) { + dev_dbg(dev->class_dev, + "subdevice %d write instruction timed out\n", + s->index); + } + } break; case INSN_BITS: if (insn->n != 2) { @@ -952,6 +1267,95 @@ out: } /* + * COMEDI_INSNLIST + * synchronous instructions + * + * arg: + * pointer to sync cmd structure + * + * reads: + * sync cmd struct at arg + * instruction list + * data (for writes) + * + * writes: + * data (for reads) + */ +/* arbitrary limits */ +#define MAX_SAMPLES 256 +static int do_insnlist_ioctl(struct comedi_device *dev, + struct comedi_insnlist __user *arg, void *file) +{ + struct comedi_insnlist insnlist; + struct comedi_insn *insns = NULL; + unsigned int *data = NULL; + int i = 0; + int ret = 0; + + if (copy_from_user(&insnlist, arg, sizeof(insnlist))) + return -EFAULT; + + data = kmalloc(sizeof(unsigned int) * MAX_SAMPLES, GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto error; + } + + insns = kcalloc(insnlist.n_insns, sizeof(*insns), GFP_KERNEL); + if (!insns) { + ret = -ENOMEM; + goto error; + } + + if (copy_from_user(insns, insnlist.insns, + sizeof(*insns) * insnlist.n_insns)) { + dev_dbg(dev->class_dev, "copy_from_user failed\n"); + ret = -EFAULT; + goto error; + } + + for (i = 0; i < insnlist.n_insns; i++) { + if (insns[i].n > MAX_SAMPLES) { + dev_dbg(dev->class_dev, + "number of samples too large\n"); + ret = -EINVAL; + goto error; + } + if (insns[i].insn & INSN_MASK_WRITE) { + if (copy_from_user(data, insns[i].data, + insns[i].n * sizeof(unsigned int))) { + dev_dbg(dev->class_dev, + "copy_from_user failed\n"); + ret = -EFAULT; + goto error; + } + } + ret = parse_insn(dev, insns + i, data, file); + if (ret < 0) + goto error; + if (insns[i].insn & INSN_MASK_READ) { + if (copy_to_user(insns[i].data, data, + insns[i].n * sizeof(unsigned int))) { + dev_dbg(dev->class_dev, + "copy_to_user failed\n"); + ret = -EFAULT; + goto error; + } + } + if (need_resched()) + schedule(); + } + +error: + kfree(insns); + kfree(data); + + if (ret < 0) + return ret; + return i; +} + +/* * COMEDI_INSN * synchronous instructions * @@ -978,7 +1382,7 @@ static int do_insn_ioctl(struct comedi_device *dev, goto error; } - if (copy_from_user(&insn, arg, sizeof(struct comedi_insn))) { + if (copy_from_user(&insn, arg, sizeof(insn))) { ret = -EFAULT; goto error; } @@ -1013,119 +1417,133 @@ error: return ret; } -static void comedi_set_subdevice_runflags(struct comedi_subdevice *s, - unsigned mask, unsigned bits) -{ - unsigned long flags; - - spin_lock_irqsave(&s->spin_lock, flags); - s->runflags &= ~mask; - s->runflags |= (bits & mask); - spin_unlock_irqrestore(&s->spin_lock, flags); -} - -static int do_cmd_ioctl(struct comedi_device *dev, - struct comedi_cmd __user *cmd, void *file) +static int __comedi_get_user_cmd(struct comedi_device *dev, + struct comedi_cmd __user *arg, + struct comedi_cmd *cmd) { - struct comedi_cmd user_cmd; struct comedi_subdevice *s; - struct comedi_async *async; - int ret = 0; - unsigned int __user *chanlist_saver = NULL; - if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) { - DPRINTK("bad cmd address\n"); + if (copy_from_user(cmd, arg, sizeof(*cmd))) { + dev_dbg(dev->class_dev, "bad cmd address\n"); return -EFAULT; } - /* save user's chanlist pointer so it can be restored later */ - chanlist_saver = user_cmd.chanlist; - if (user_cmd.subdev >= dev->n_subdevices) { - DPRINTK("%d no such subdevice\n", user_cmd.subdev); + if (cmd->subdev >= dev->n_subdevices) { + dev_dbg(dev->class_dev, "%d no such subdevice\n", cmd->subdev); return -ENODEV; } - s = dev->subdevices + user_cmd.subdev; - async = s->async; + s = &dev->subdevices[cmd->subdev]; if (s->type == COMEDI_SUBD_UNUSED) { - DPRINTK("%d not valid subdevice\n", user_cmd.subdev); + dev_dbg(dev->class_dev, "%d not valid subdevice\n", + cmd->subdev); return -EIO; } if (!s->do_cmd || !s->do_cmdtest || !s->async) { - DPRINTK("subdevice %i does not support commands\n", - user_cmd.subdev); + dev_dbg(dev->class_dev, + "subdevice %d does not support commands\n", + cmd->subdev); return -EIO; } + /* make sure channel/gain list isn't too long */ + if (cmd->chanlist_len > s->len_chanlist) { + dev_dbg(dev->class_dev, "channel/gain list too long %d > %d\n", + cmd->chanlist_len, s->len_chanlist); + return -EINVAL; + } + + return 0; +} + +static int __comedi_get_user_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int __user *user_chanlist, + struct comedi_cmd *cmd) +{ + unsigned int *chanlist; + int ret; + + /* user_chanlist could be NULL for do_cmdtest ioctls */ + if (!user_chanlist) + return 0; + + chanlist = memdup_user(user_chanlist, + cmd->chanlist_len * sizeof(unsigned int)); + if (IS_ERR(chanlist)) + return PTR_ERR(chanlist); + + /* make sure each element in channel/gain list is valid */ + ret = comedi_check_chanlist(s, cmd->chanlist_len, chanlist); + if (ret < 0) { + kfree(chanlist); + return ret; + } + + cmd->chanlist = chanlist; + + return 0; +} + +static int do_cmd_ioctl(struct comedi_device *dev, + struct comedi_cmd __user *arg, void *file) +{ + struct comedi_cmd cmd; + struct comedi_subdevice *s; + struct comedi_async *async; + unsigned int __user *user_chanlist; + int ret; + + /* get the user's cmd and do some simple validation */ + ret = __comedi_get_user_cmd(dev, arg, &cmd); + if (ret) + return ret; + + /* save user's chanlist pointer so it can be restored later */ + user_chanlist = (unsigned int __user *)cmd.chanlist; + + s = &dev->subdevices[cmd.subdev]; + async = s->async; + /* are we locked? (ioctl lock) */ if (s->lock && s->lock != file) { - DPRINTK("subdevice locked\n"); + dev_dbg(dev->class_dev, "subdevice locked\n"); return -EACCES; } /* are we busy? */ if (s->busy) { - DPRINTK("subdevice busy\n"); + dev_dbg(dev->class_dev, "subdevice busy\n"); return -EBUSY; } - s->busy = file; - - /* make sure channel/gain list isn't too long */ - if (user_cmd.chanlist_len > s->len_chanlist) { - DPRINTK("channel/gain list too long %u > %d\n", - user_cmd.chanlist_len, s->len_chanlist); - ret = -EINVAL; - goto cleanup; - } /* make sure channel/gain list isn't too short */ - if (user_cmd.chanlist_len < 1) { - DPRINTK("channel/gain list too short %u < 1\n", - user_cmd.chanlist_len); - ret = -EINVAL; - goto cleanup; + if (cmd.chanlist_len < 1) { + dev_dbg(dev->class_dev, "channel/gain list too short %u < 1\n", + cmd.chanlist_len); + return -EINVAL; } - kfree(async->cmd.chanlist); - async->cmd = user_cmd; + async->cmd = cmd; async->cmd.data = NULL; - /* load channel/gain list */ - async->cmd.chanlist = - kmalloc(async->cmd.chanlist_len * sizeof(int), GFP_KERNEL); - if (!async->cmd.chanlist) { - DPRINTK("allocation failed\n"); - ret = -ENOMEM; - goto cleanup; - } - if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist, - async->cmd.chanlist_len * sizeof(int))) { - DPRINTK("fault reading chanlist\n"); - ret = -EFAULT; - goto cleanup; - } - - /* make sure each element in channel/gain list is valid */ - ret = comedi_check_chanlist(s, - async->cmd.chanlist_len, - async->cmd.chanlist); - if (ret < 0) { - DPRINTK("bad chanlist\n"); + /* load channel/gain list */ + ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &async->cmd); + if (ret) goto cleanup; - } ret = s->do_cmdtest(dev, s, &async->cmd); if (async->cmd.flags & TRIG_BOGUS || ret) { - DPRINTK("test returned %d\n", ret); - user_cmd = async->cmd; + dev_dbg(dev->class_dev, "test returned %d\n", ret); + cmd = async->cmd; /* restore chanlist pointer before copying back */ - user_cmd.chanlist = chanlist_saver; - user_cmd.data = NULL; - if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) { - DPRINTK("fault writing cmd\n"); + cmd.chanlist = (unsigned int __force *)user_chanlist; + cmd.data = NULL; + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + dev_dbg(dev->class_dev, "fault writing cmd\n"); ret = -EFAULT; goto cleanup; } @@ -1135,11 +1553,11 @@ static int do_cmd_ioctl(struct comedi_device *dev, if (!async->prealloc_bufsz) { ret = -ENOMEM; - DPRINTK("no buffer (?)\n"); + dev_dbg(dev->class_dev, "no buffer (?)\n"); goto cleanup; } - comedi_reset_async_buf(async); + comedi_buf_reset(s); async->cb_mask = COMEDI_CB_EOA | COMEDI_CB_BLOCK | COMEDI_CB_ERROR | @@ -1147,8 +1565,11 @@ static int do_cmd_ioctl(struct comedi_device *dev, if (async->cmd.flags & TRIG_WAKE_EOS) async->cb_mask |= COMEDI_CB_EOS; - comedi_set_subdevice_runflags(s, ~0, SRF_USER | SRF_RUNNING); + comedi_set_subdevice_runflags(s, SRF_ERROR | SRF_RUNNING, SRF_RUNNING); + /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with + * comedi_read() or comedi_write() */ + s->busy = file; ret = s->do_cmd(dev, s); if (ret == 0) return 0; @@ -1177,83 +1598,35 @@ cleanup: static int do_cmdtest_ioctl(struct comedi_device *dev, struct comedi_cmd __user *arg, void *file) { - struct comedi_cmd user_cmd; + struct comedi_cmd cmd; struct comedi_subdevice *s; - int ret = 0; - unsigned int *chanlist = NULL; - unsigned int __user *chanlist_saver = NULL; - - if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) { - DPRINTK("bad cmd address\n"); - return -EFAULT; - } - /* save user's chanlist pointer so it can be restored later */ - chanlist_saver = user_cmd.chanlist; - - if (user_cmd.subdev >= dev->n_subdevices) { - DPRINTK("%d no such subdevice\n", user_cmd.subdev); - return -ENODEV; - } + unsigned int __user *user_chanlist; + int ret; - s = dev->subdevices + user_cmd.subdev; - if (s->type == COMEDI_SUBD_UNUSED) { - DPRINTK("%d not valid subdevice\n", user_cmd.subdev); - return -EIO; - } + /* get the user's cmd and do some simple validation */ + ret = __comedi_get_user_cmd(dev, arg, &cmd); + if (ret) + return ret; - if (!s->do_cmd || !s->do_cmdtest) { - DPRINTK("subdevice %i does not support commands\n", - user_cmd.subdev); - return -EIO; - } + /* save user's chanlist pointer so it can be restored later */ + user_chanlist = (unsigned int __user *)cmd.chanlist; - /* make sure channel/gain list isn't too long */ - if (user_cmd.chanlist_len > s->len_chanlist) { - DPRINTK("channel/gain list too long %d > %d\n", - user_cmd.chanlist_len, s->len_chanlist); - ret = -EINVAL; - goto cleanup; - } + s = &dev->subdevices[cmd.subdev]; /* load channel/gain list */ - if (user_cmd.chanlist) { - chanlist = - kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL); - if (!chanlist) { - DPRINTK("allocation failed\n"); - ret = -ENOMEM; - goto cleanup; - } - - if (copy_from_user(chanlist, user_cmd.chanlist, - user_cmd.chanlist_len * sizeof(int))) { - DPRINTK("fault reading chanlist\n"); - ret = -EFAULT; - goto cleanup; - } - - /* make sure each element in channel/gain list is valid */ - ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist); - if (ret < 0) { - DPRINTK("bad chanlist\n"); - goto cleanup; - } - - user_cmd.chanlist = chanlist; - } + ret = __comedi_get_user_chanlist(dev, s, user_chanlist, &cmd); + if (ret) + return ret; - ret = s->do_cmdtest(dev, s, &user_cmd); + ret = s->do_cmdtest(dev, s, &cmd); /* restore chanlist pointer before copying back */ - user_cmd.chanlist = chanlist_saver; + cmd.chanlist = (unsigned int __force *)user_chanlist; - if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) { - DPRINTK("bad cmd address\n"); + if (copy_to_user(arg, &cmd, sizeof(cmd))) { + dev_dbg(dev->class_dev, "bad cmd address\n"); ret = -EFAULT; - goto cleanup; } -cleanup: - kfree(chanlist); return ret; } @@ -1282,7 +1655,7 @@ static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, if (arg >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + arg; + s = &dev->subdevices[arg]; spin_lock_irqsave(&s->spin_lock, flags); if (s->busy || s->lock) @@ -1291,10 +1664,10 @@ static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, s->lock = file; spin_unlock_irqrestore(&s->spin_lock, flags); +#if 0 if (ret < 0) return ret; -#if 0 if (s->lock_f) ret = s->lock_f(dev, s); #endif @@ -1325,7 +1698,7 @@ static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, if (arg >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + arg; + s = &dev->subdevices[arg]; if (s->busy) return -EBUSY; @@ -1363,10 +1736,11 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, void *file) { struct comedi_subdevice *s; + int ret; if (arg >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + arg; + s = &dev->subdevices[arg]; if (s->async == NULL) return -EINVAL; @@ -1379,7 +1753,9 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, if (s->busy != file) return -EBUSY; - return do_cancel(dev, s); + ret = do_cancel(dev, s); + + return ret; } /* @@ -1403,7 +1779,7 @@ static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, if (arg >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + arg; + s = &dev->subdevices[arg]; if (s->lock && s->lock != file) return -EACCES; @@ -1420,72 +1796,175 @@ static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, return -EINVAL; } -static int do_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { - int ret = 0; + const unsigned minor = iminor(file_inode(file)); + struct comedi_device *dev = file->private_data; + int rc; - if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) && s->cancel) - ret = s->cancel(dev, s); + mutex_lock(&dev->mutex); - do_become_nonbusy(dev, s); + /* Device config is special, because it must work on + * an unconfigured device. */ + if (cmd == COMEDI_DEVCONFIG) { + if (minor >= COMEDI_NUM_BOARD_MINORS) { + /* Device config not appropriate on non-board minors. */ + rc = -ENOTTY; + goto done; + } + rc = do_devconfig_ioctl(dev, + (struct comedi_devconfig __user *)arg); + if (rc == 0) { + if (arg == 0 && + dev->minor >= comedi_num_legacy_minors) { + /* Successfully unconfigured a dynamically + * allocated device. Try and remove it. */ + if (comedi_clear_board_dev(dev)) { + mutex_unlock(&dev->mutex); + comedi_free_board_dev(dev); + return rc; + } + } + } + goto done; + } - return ret; + if (!dev->attached) { + dev_dbg(dev->class_dev, "no driver attached\n"); + rc = -ENODEV; + goto done; + } + + switch (cmd) { + case COMEDI_BUFCONFIG: + rc = do_bufconfig_ioctl(dev, + (struct comedi_bufconfig __user *)arg); + break; + case COMEDI_DEVINFO: + rc = do_devinfo_ioctl(dev, (struct comedi_devinfo __user *)arg, + file); + break; + case COMEDI_SUBDINFO: + rc = do_subdinfo_ioctl(dev, + (struct comedi_subdinfo __user *)arg, + file); + break; + case COMEDI_CHANINFO: + rc = do_chaninfo_ioctl(dev, (void __user *)arg); + break; + case COMEDI_RANGEINFO: + rc = do_rangeinfo_ioctl(dev, (void __user *)arg); + break; + case COMEDI_BUFINFO: + rc = do_bufinfo_ioctl(dev, + (struct comedi_bufinfo __user *)arg, + file); + break; + case COMEDI_LOCK: + rc = do_lock_ioctl(dev, arg, file); + break; + case COMEDI_UNLOCK: + rc = do_unlock_ioctl(dev, arg, file); + break; + case COMEDI_CANCEL: + rc = do_cancel_ioctl(dev, arg, file); + break; + case COMEDI_CMD: + rc = do_cmd_ioctl(dev, (struct comedi_cmd __user *)arg, file); + break; + case COMEDI_CMDTEST: + rc = do_cmdtest_ioctl(dev, (struct comedi_cmd __user *)arg, + file); + break; + case COMEDI_INSNLIST: + rc = do_insnlist_ioctl(dev, + (struct comedi_insnlist __user *)arg, + file); + break; + case COMEDI_INSN: + rc = do_insn_ioctl(dev, (struct comedi_insn __user *)arg, + file); + break; + case COMEDI_POLL: + rc = do_poll_ioctl(dev, arg, file); + break; + default: + rc = -ENOTTY; + break; + } + +done: + mutex_unlock(&dev->mutex); + return rc; } -static void comedi_unmap(struct vm_area_struct *area) +static void comedi_vm_open(struct vm_area_struct *area) { - struct comedi_async *async; - struct comedi_device *dev; + struct comedi_buf_map *bm; - async = area->vm_private_data; - dev = async->subdevice->device; + bm = area->vm_private_data; + comedi_buf_map_get(bm); +} - mutex_lock(&dev->mutex); - async->mmap_count--; - mutex_unlock(&dev->mutex); +static void comedi_vm_close(struct vm_area_struct *area) +{ + struct comedi_buf_map *bm; + + bm = area->vm_private_data; + comedi_buf_map_put(bm); } static struct vm_operations_struct comedi_vm_ops = { - .close = comedi_unmap, + .open = comedi_vm_open, + .close = comedi_vm_close, }; static int comedi_mmap(struct file *file, struct vm_area_struct *vma) { - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; - struct comedi_async *async = NULL; + const unsigned minor = iminor(file_inode(file)); + struct comedi_device *dev = file->private_data; + struct comedi_subdevice *s; + struct comedi_async *async; + struct comedi_buf_map *bm = NULL; unsigned long start = vma->vm_start; unsigned long size; int n_pages; int i; int retval; - struct comedi_subdevice *s; - mutex_lock(&dev->mutex); + /* + * 'trylock' avoids circular dependency with current->mm->mmap_sem + * and down-reading &dev->attach_lock should normally succeed without + * contention unless the device is in the process of being attached + * or detached. + */ + if (!down_read_trylock(&dev->attach_lock)) + return -EAGAIN; + if (!dev->attached) { - DPRINTK("no driver configured on comedi%i\n", dev->minor); + dev_dbg(dev->class_dev, "no driver attached\n"); retval = -ENODEV; goto done; } + if (vma->vm_flags & VM_WRITE) - s = comedi_get_write_subdevice(dev_file_info); + s = comedi_write_subdevice(dev, minor); else - s = comedi_get_read_subdevice(dev_file_info); - - if (s == NULL) { + s = comedi_read_subdevice(dev, minor); + if (!s) { retval = -EINVAL; goto done; } + async = s->async; - if (async == NULL) { + if (!async) { retval = -EINVAL; goto done; } if (vma->vm_pgoff != 0) { - DPRINTK("comedi: mmap() offset must be 0.\n"); + dev_dbg(dev->class_dev, "mmap() offset must be 0.\n"); retval = -EINVAL; goto done; } @@ -1501,12 +1980,19 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) } n_pages = size >> PAGE_SHIFT; + + /* get reference to current buf map (if any) */ + bm = comedi_buf_map_from_subdev_get(s); + if (!bm || n_pages > bm->n_pages) { + retval = -EINVAL; + goto done; + } for (i = 0; i < n_pages; ++i) { + struct comedi_buf_page *buf = &bm->page_list[i]; + if (remap_pfn_range(vma, start, - page_to_pfn(virt_to_page - (async->buf_page_list - [i].virt_addr)), PAGE_SIZE, - PAGE_SHARED)) { + page_to_pfn(virt_to_page(buf->virt_addr)), + PAGE_SIZE, PAGE_SHARED)) { retval = -EAGAIN; goto done; } @@ -1514,58 +2000,51 @@ static int comedi_mmap(struct file *file, struct vm_area_struct *vma) } vma->vm_ops = &comedi_vm_ops; - vma->vm_private_data = async; + vma->vm_private_data = bm; - async->mmap_count++; + vma->vm_ops->open(vma); retval = 0; done: - mutex_unlock(&dev->mutex); + up_read(&dev->attach_lock); + comedi_buf_map_put(bm); /* put reference to buf map - okay if NULL */ return retval; } -static unsigned int comedi_poll(struct file *file, poll_table * wait) +static unsigned int comedi_poll(struct file *file, poll_table *wait) { unsigned int mask = 0; - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; - struct comedi_subdevice *read_subdev; - struct comedi_subdevice *write_subdev; + const unsigned minor = iminor(file_inode(file)); + struct comedi_device *dev = file->private_data; + struct comedi_subdevice *s; mutex_lock(&dev->mutex); + if (!dev->attached) { - DPRINTK("no driver configured on comedi%i\n", dev->minor); - mutex_unlock(&dev->mutex); - return 0; + dev_dbg(dev->class_dev, "no driver attached\n"); + goto done; } - mask = 0; - read_subdev = comedi_get_read_subdevice(dev_file_info); - if (read_subdev) { - poll_wait(file, &read_subdev->async->wait_head, wait); - if (!read_subdev->busy - || comedi_buf_read_n_available(read_subdev->async) > 0 - || !(comedi_get_subdevice_runflags(read_subdev) & - SRF_RUNNING)) { + s = comedi_read_subdevice(dev, minor); + if (s && s->async) { + poll_wait(file, &s->async->wait_head, wait); + if (!s->busy || !comedi_is_subdevice_running(s) || + comedi_buf_read_n_available(s) > 0) mask |= POLLIN | POLLRDNORM; - } } - write_subdev = comedi_get_write_subdevice(dev_file_info); - if (write_subdev) { - poll_wait(file, &write_subdev->async->wait_head, wait); - comedi_buf_write_alloc(write_subdev->async, - write_subdev->async->prealloc_bufsz); - if (!write_subdev->busy - || !(comedi_get_subdevice_runflags(write_subdev) & - SRF_RUNNING) - || comedi_buf_write_n_allocated(write_subdev->async) >= - bytes_per_sample(write_subdev->async->subdevice)) { + + s = comedi_write_subdevice(dev, minor); + if (s && s->async) { + unsigned int bps = bytes_per_sample(s); + + poll_wait(file, &s->async->wait_head, wait); + comedi_buf_write_alloc(s, s->async->prealloc_bufsz); + if (!s->busy || !comedi_is_subdevice_running(s) || + comedi_buf_write_n_allocated(s) >= bps) mask |= POLLOUT | POLLWRNORM; - } } +done: mutex_unlock(&dev->mutex); return mask; } @@ -1577,49 +2056,77 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, struct comedi_async *async; int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + const unsigned minor = iminor(file_inode(file)); + struct comedi_device *dev = file->private_data; + bool on_wait_queue = false; + bool attach_locked; + unsigned int old_detach_count; + + /* Protect against device detachment during operation. */ + down_read(&dev->attach_lock); + attach_locked = true; + old_detach_count = dev->detach_count; if (!dev->attached) { - DPRINTK("no driver configured on comedi%i\n", dev->minor); + dev_dbg(dev->class_dev, "no driver attached\n"); retval = -ENODEV; - goto done; + goto out; } - s = comedi_get_write_subdevice(dev_file_info); - if (s == NULL) { + s = comedi_write_subdevice(dev, minor); + if (!s || !s->async) { retval = -EIO; - goto done; + goto out; } + async = s->async; - if (!nbytes) { - retval = 0; - goto done; - } - if (!s->busy) { - retval = 0; - goto done; - } + if (!s->busy || !nbytes) + goto out; if (s->busy != file) { retval = -EACCES; - goto done; + goto out; } + add_wait_queue(&async->wait_head, &wait); + on_wait_queue = true; while (nbytes > 0 && !retval) { set_current_state(TASK_INTERRUPTIBLE); - if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { + if (!comedi_is_subdevice_running(s)) { if (count == 0) { - if (comedi_get_subdevice_runflags(s) & - SRF_ERROR) { + struct comedi_subdevice *new_s; + + if (comedi_is_subdevice_in_error(s)) retval = -EPIPE; - } else { + else retval = 0; - } - do_become_nonbusy(dev, s); + /* + * To avoid deadlock, cannot acquire dev->mutex + * while dev->attach_lock is held. Need to + * remove task from the async wait queue before + * releasing dev->attach_lock, as it might not + * be valid afterwards. + */ + remove_wait_queue(&async->wait_head, &wait); + on_wait_queue = false; + up_read(&dev->attach_lock); + attach_locked = false; + mutex_lock(&dev->mutex); + /* + * Become non-busy unless things have changed + * behind our back. Checking dev->detach_count + * is unchanged ought to be sufficient (unless + * there have been 2**32 detaches in the + * meantime!), but check the subdevice pointer + * as well just in case. + */ + new_s = comedi_write_subdevice(dev, minor); + if (dev->attached && + old_detach_count == dev->detach_count && + s == new_s && new_s->async == async) + do_become_nonbusy(dev, s); + mutex_unlock(&dev->mutex); } break; } @@ -1629,9 +2136,9 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, m = n; if (async->buf_write_ptr + m > async->prealloc_bufsz) m = async->prealloc_bufsz - async->buf_write_ptr; - comedi_buf_write_alloc(async, async->prealloc_bufsz); - if (m > comedi_buf_write_n_allocated(async)) - m = comedi_buf_write_n_allocated(async); + comedi_buf_write_alloc(s, async->prealloc_bufsz); + if (m > comedi_buf_write_n_allocated(s)) + m = comedi_buf_write_n_allocated(s); if (m < n) n = m; @@ -1640,11 +2147,11 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, retval = -EAGAIN; break; } + schedule(); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } - schedule(); if (!s->busy) break; if (s->busy != file) { @@ -1660,7 +2167,7 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, n -= m; retval = -EFAULT; } - comedi_buf_write_free(async, n); + comedi_buf_write_free(s, n); count += n; nbytes -= n; @@ -1668,10 +2175,13 @@ static ssize_t comedi_write(struct file *file, const char __user *buf, buf += n; break; /* makes device work like a pipe */ } +out: + if (on_wait_queue) + remove_wait_queue(&async->wait_head, &wait); set_current_state(TASK_RUNNING); - remove_wait_queue(&async->wait_head, &wait); + if (attach_locked) + up_read(&dev->attach_lock); -done: return count ? count : retval; } @@ -1682,34 +2192,35 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, struct comedi_async *async; int n, m, count = 0, retval = 0; DECLARE_WAITQUEUE(wait, current); - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + const unsigned minor = iminor(file_inode(file)); + struct comedi_device *dev = file->private_data; + unsigned int old_detach_count; + bool become_nonbusy = false; + bool attach_locked; + + /* Protect against device detachment during operation. */ + down_read(&dev->attach_lock); + attach_locked = true; + old_detach_count = dev->detach_count; if (!dev->attached) { - DPRINTK("no driver configured on comedi%i\n", dev->minor); + dev_dbg(dev->class_dev, "no driver attached\n"); retval = -ENODEV; - goto done; + goto out; } - s = comedi_get_read_subdevice(dev_file_info); - if (s == NULL) { + s = comedi_read_subdevice(dev, minor); + if (!s || !s->async) { retval = -EIO; - goto done; + goto out; } + async = s->async; - if (!nbytes) { - retval = 0; - goto done; - } - if (!s->busy) { - retval = 0; - goto done; - } + if (!s->busy || !nbytes) + goto out; if (s->busy != file) { retval = -EACCES; - goto done; + goto out; } add_wait_queue(&async->wait_head, &wait); @@ -1718,7 +2229,7 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, n = nbytes; - m = comedi_buf_read_n_available(async); + m = comedi_buf_read_n_available(s); /* printk("%d available\n",m); */ if (async->buf_read_ptr + m > async->prealloc_bufsz) m = async->prealloc_bufsz - async->buf_read_ptr; @@ -1727,25 +2238,23 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, n = m; if (n == 0) { - if (!(comedi_get_subdevice_runflags(s) & SRF_RUNNING)) { - do_become_nonbusy(dev, s); - if (comedi_get_subdevice_runflags(s) & - SRF_ERROR) { + if (!comedi_is_subdevice_running(s)) { + if (comedi_is_subdevice_in_error(s)) retval = -EPIPE; - } else { + else retval = 0; - } + become_nonbusy = true; break; } if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; break; } + schedule(); if (signal_pending(current)) { retval = -ERESTARTSYS; break; } - schedule(); if (!s->busy) { retval = 0; break; @@ -1763,8 +2272,8 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, retval = -EFAULT; } - comedi_buf_read_alloc(async, n); - comedi_buf_read_free(async, n); + comedi_buf_read_alloc(s, n); + comedi_buf_read_free(s, n); count += n; nbytes -= n; @@ -1772,122 +2281,93 @@ static ssize_t comedi_read(struct file *file, char __user *buf, size_t nbytes, buf += n; break; /* makes device work like a pipe */ } - if (!(comedi_get_subdevice_runflags(s) & (SRF_ERROR | SRF_RUNNING)) && - async->buf_read_count - async->buf_write_count == 0) { - do_become_nonbusy(dev, s); - } - set_current_state(TASK_RUNNING); remove_wait_queue(&async->wait_head, &wait); - -done: - return count ? count : retval; -} - -/* - This function restores a subdevice to an idle state. - */ -void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct comedi_async *async = s->async; - - comedi_set_subdevice_runflags(s, SRF_RUNNING, 0); - if (async) { - comedi_reset_async_buf(async); - async->inttrig = NULL; - } else { - printk(KERN_ERR - "BUG: (?) do_become_nonbusy called with async=0\n"); + set_current_state(TASK_RUNNING); + if (become_nonbusy || comedi_is_subdevice_idle(s)) { + struct comedi_subdevice *new_s; + + /* + * To avoid deadlock, cannot acquire dev->mutex + * while dev->attach_lock is held. + */ + up_read(&dev->attach_lock); + attach_locked = false; + mutex_lock(&dev->mutex); + /* + * Check device hasn't become detached behind our back. + * Checking dev->detach_count is unchanged ought to be + * sufficient (unless there have been 2**32 detaches in the + * meantime!), but check the subdevice pointer as well just in + * case. + */ + new_s = comedi_read_subdevice(dev, minor); + if (dev->attached && old_detach_count == dev->detach_count && + s == new_s && new_s->async == async) { + if (become_nonbusy || + async->buf_read_count - async->buf_write_count == 0) + do_become_nonbusy(dev, s); + } + mutex_unlock(&dev->mutex); } +out: + if (attach_locked) + up_read(&dev->attach_lock); - s->busy = NULL; + return count ? count : retval; } static int comedi_open(struct inode *inode, struct file *file) { const unsigned minor = iminor(inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = - dev_file_info ? dev_file_info->device : NULL; - - if (dev == NULL) { - DPRINTK("invalid minor number\n"); - return -ENODEV; - } + struct comedi_device *dev = comedi_dev_get_from_minor(minor); + int rc; - /* This is slightly hacky, but we want module autoloading - * to work for root. - * case: user opens device, attached -> ok - * case: user opens device, unattached, in_request_module=0 -> autoload - * case: user opens device, unattached, in_request_module=1 -> fail - * case: root opens device, attached -> ok - * case: root opens device, unattached, in_request_module=1 -> ok - * (typically called from modprobe) - * case: root opens device, unattached, in_request_module=0 -> autoload - * - * The last could be changed to "-> ok", which would deny root - * autoloading. - */ - mutex_lock(&dev->mutex); - if (dev->attached) - goto ok; - if (!capable(CAP_NET_ADMIN) && dev->in_request_module) { - DPRINTK("in request module\n"); - mutex_unlock(&dev->mutex); + if (!dev) { + pr_debug("invalid minor number\n"); return -ENODEV; } - if (capable(CAP_NET_ADMIN) && dev->in_request_module) - goto ok; - dev->in_request_module = 1; - -#ifdef CONFIG_KMOD - mutex_unlock(&dev->mutex); - request_module("char-major-%i-%i", COMEDI_MAJOR, dev->minor); mutex_lock(&dev->mutex); -#endif - - dev->in_request_module = 0; - if (!dev->attached && !capable(CAP_NET_ADMIN)) { - DPRINTK("not attached and not CAP_NET_ADMIN\n"); - mutex_unlock(&dev->mutex); - return -ENODEV; + dev_dbg(dev->class_dev, "not attached and not CAP_NET_ADMIN\n"); + rc = -ENODEV; + goto out; } -ok: - __module_get(THIS_MODULE); - - if (dev->attached) { + if (dev->attached && dev->use_count == 0) { if (!try_module_get(dev->driver->module)) { - module_put(THIS_MODULE); - mutex_unlock(&dev->mutex); - return -ENOSYS; + rc = -ENOSYS; + goto out; } - } - - if (dev->attached && dev->use_count == 0 && dev->open) { - int rc = dev->open(dev); - if (rc < 0) { - module_put(dev->driver->module); - module_put(THIS_MODULE); - mutex_unlock(&dev->mutex); - return rc; + if (dev->open) { + rc = dev->open(dev); + if (rc < 0) { + module_put(dev->driver->module); + goto out; + } } } dev->use_count++; + file->private_data = dev; + rc = 0; +out: mutex_unlock(&dev->mutex); + if (rc) + comedi_dev_put(dev); + return rc; +} - return 0; +static int comedi_fasync(int fd, struct file *file, int on) +{ + struct comedi_device *dev = file->private_data; + + return fasync_helper(fd, file, on, &dev->async_queue); } static int comedi_close(struct inode *inode, struct file *file) { - const unsigned minor = iminor(inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - struct comedi_device *dev = dev_file_info->device; + struct comedi_device *dev = file->private_data; struct comedi_subdevice *s = NULL; int i; @@ -1895,7 +2375,7 @@ static int comedi_close(struct inode *inode, struct file *file) if (dev->subdevices) { for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; if (s->busy == file) do_cancel(dev, s); @@ -1903,35 +2383,21 @@ static int comedi_close(struct inode *inode, struct file *file) s->lock = NULL; } } - if (dev->attached && dev->use_count == 1 && dev->close) - dev->close(dev); - - module_put(THIS_MODULE); - if (dev->attached) + if (dev->attached && dev->use_count == 1) { + if (dev->close) + dev->close(dev); module_put(dev->driver->module); + } dev->use_count--; mutex_unlock(&dev->mutex); - - if (file->f_flags & FASYNC) - comedi_fasync(-1, file, 0); + comedi_dev_put(dev); return 0; } -static int comedi_fasync(int fd, struct file *file, int on) -{ - const unsigned minor = iminor(file->f_dentry->d_inode); - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(minor); - - struct comedi_device *dev = dev_file_info->device; - - return fasync_helper(fd, file, on, &dev->async_queue); -} - -const struct file_operations comedi_fops = { +static const struct file_operations comedi_fops = { .owner = THIS_MODULE, .unlocked_ioctl = comedi_unlocked_ioctl, .compat_ioctl = comedi_compat_ioctl, @@ -1945,108 +2411,11 @@ const struct file_operations comedi_fops = { .llseek = noop_llseek, }; -struct class *comedi_class; -static struct cdev comedi_cdev; - -static void comedi_cleanup_legacy_minors(void) -{ - unsigned i; - - for (i = 0; i < comedi_num_legacy_minors; i++) - comedi_free_board_minor(i); -} - -static int __init comedi_init(void) -{ - int i; - int retval; - - printk(KERN_INFO "comedi: version " COMEDI_RELEASE - " - http://www.comedi.org\n"); - - if (comedi_num_legacy_minors < 0 || - comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { - printk(KERN_ERR "comedi: error: invalid value for module " - "parameter \"comedi_num_legacy_minors\". Valid values " - "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); - return -EINVAL; - } - - /* - * comedi is unusable if both comedi_autoconfig and - * comedi_num_legacy_minors are zero, so we might as well adjust the - * defaults in that case - */ - if (comedi_autoconfig == 0 && comedi_num_legacy_minors == 0) - comedi_num_legacy_minors = 16; - - memset(comedi_file_info_table, 0, - sizeof(struct comedi_device_file_info *) * COMEDI_NUM_MINORS); - - retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS, "comedi"); - if (retval) - return -EIO; - cdev_init(&comedi_cdev, &comedi_fops); - comedi_cdev.owner = THIS_MODULE; - kobject_set_name(&comedi_cdev.kobj, "comedi"); - if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return -EIO; - } - comedi_class = class_create(THIS_MODULE, "comedi"); - if (IS_ERR(comedi_class)) { - printk(KERN_ERR "comedi: failed to create class"); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return PTR_ERR(comedi_class); - } - - /* XXX requires /proc interface */ - comedi_proc_init(); - - /* create devices files for legacy/manual use */ - for (i = 0; i < comedi_num_legacy_minors; i++) { - int minor; - minor = comedi_alloc_board_minor(NULL); - if (minor < 0) { - comedi_cleanup_legacy_minors(); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), - COMEDI_NUM_MINORS); - return minor; - } - } - - return 0; -} - -static void __exit comedi_cleanup(void) -{ - int i; - - comedi_cleanup_legacy_minors(); - for (i = 0; i < COMEDI_NUM_MINORS; ++i) - BUG_ON(comedi_file_info_table[i]); - - class_destroy(comedi_class); - cdev_del(&comedi_cdev); - unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); - - comedi_proc_cleanup(); -} - -module_init(comedi_init); -module_exit(comedi_cleanup); - void comedi_error(const struct comedi_device *dev, const char *s) { - printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor, - dev->driver->driver_name, s); + dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s); } -EXPORT_SYMBOL(comedi_error); +EXPORT_SYMBOL_GPL(comedi_error); void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -2054,9 +2423,7 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) unsigned runflags = 0; unsigned runflags_mask = 0; - /* DPRINTK("comedi_event 0x%x\n",mask); */ - - if ((comedi_get_subdevice_runflags(s) & SRF_RUNNING) == 0) + if (!comedi_is_subdevice_running(s)) return; if (s-> @@ -2076,256 +2443,112 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s) } if (async->cb_mask & s->async->events) { - if (comedi_get_subdevice_runflags(s) & SRF_USER) { - wake_up_interruptible(&async->wait_head); - if (s->subdev_flags & SDF_CMD_READ) - kill_fasync(&dev->async_queue, SIGIO, POLL_IN); - if (s->subdev_flags & SDF_CMD_WRITE) - kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); - } else { - if (async->cb_func) - async->cb_func(s->async->events, async->cb_arg); - } + wake_up_interruptible(&async->wait_head); + if (s->subdev_flags & SDF_CMD_READ) + kill_fasync(&dev->async_queue, SIGIO, POLL_IN); + if (s->subdev_flags & SDF_CMD_WRITE) + kill_fasync(&dev->async_queue, SIGIO, POLL_OUT); } s->async->events = 0; } -EXPORT_SYMBOL(comedi_event); - -unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s) -{ - unsigned long flags; - unsigned runflags; - - spin_lock_irqsave(&s->spin_lock, flags); - runflags = s->runflags; - spin_unlock_irqrestore(&s->spin_lock, flags); - return runflags; -} -EXPORT_SYMBOL(comedi_get_subdevice_runflags); +EXPORT_SYMBOL_GPL(comedi_event); -static int is_device_busy(struct comedi_device *dev) +/* Note: the ->mutex is pre-locked on successful return */ +struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device) { - struct comedi_subdevice *s; - int i; - - if (!dev->attached) - return 0; - - for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; - if (s->busy) - return 1; - if (s->async && s->async->mmap_count) - return 1; - } - - return 0; -} - -static void comedi_device_init(struct comedi_device *dev) -{ - memset(dev, 0, sizeof(struct comedi_device)); - spin_lock_init(&dev->spinlock); - mutex_init(&dev->mutex); - dev->minor = -1; -} - -static void comedi_device_cleanup(struct comedi_device *dev) -{ - if (dev == NULL) - return; - mutex_lock(&dev->mutex); - comedi_device_detach(dev); - mutex_unlock(&dev->mutex); - mutex_destroy(&dev->mutex); -} - -int comedi_alloc_board_minor(struct device *hardware_device) -{ - unsigned long flags; - struct comedi_device_file_info *info; + struct comedi_device *dev; struct device *csdev; unsigned i; - int retval; - info = kzalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); - if (info == NULL) - return -ENOMEM; - info->device = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); - if (info->device == NULL) { - kfree(info); - return -ENOMEM; - } - comedi_device_init(info->device); - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) { - if (comedi_file_info_table[i] == NULL) { - comedi_file_info_table[i] = info; + dev = kzalloc(sizeof(struct comedi_device), GFP_KERNEL); + if (dev == NULL) + return ERR_PTR(-ENOMEM); + comedi_device_init(dev); + comedi_set_hw_dev(dev, hardware_device); + mutex_lock(&dev->mutex); + mutex_lock(&comedi_board_minor_table_lock); + for (i = hardware_device ? comedi_num_legacy_minors : 0; + i < COMEDI_NUM_BOARD_MINORS; ++i) { + if (comedi_board_minor_table[i] == NULL) { + comedi_board_minor_table[i] = dev; break; } } - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + mutex_unlock(&comedi_board_minor_table_lock); if (i == COMEDI_NUM_BOARD_MINORS) { - comedi_device_cleanup(info->device); - kfree(info->device); - kfree(info); - printk(KERN_ERR - "comedi: error: " - "ran out of minor numbers for board device files.\n"); - return -EBUSY; - } - info->device->minor = i; - csdev = COMEDI_DEVICE_CREATE(comedi_class, NULL, - MKDEV(COMEDI_MAJOR, i), NULL, - hardware_device, "comedi%i", i); + mutex_unlock(&dev->mutex); + comedi_device_cleanup(dev); + comedi_dev_put(dev); + pr_err("comedi: error: ran out of minor numbers for board device files.\n"); + return ERR_PTR(-EBUSY); + } + dev->minor = i; + csdev = device_create(comedi_class, hardware_device, + MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i", i); if (!IS_ERR(csdev)) - info->device->class_dev = csdev; - dev_set_drvdata(csdev, info); - retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_max_read_buffer_kb.attr.name); - comedi_free_board_minor(i); - return retval; - } - retval = device_create_file(csdev, &dev_attr_read_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_read_buffer_kb.attr.name); - comedi_free_board_minor(i); - return retval; - } - retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_max_write_buffer_kb.attr.name); - comedi_free_board_minor(i); - return retval; - } - retval = device_create_file(csdev, &dev_attr_write_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_write_buffer_kb.attr.name); - comedi_free_board_minor(i); - return retval; - } - return i; + dev->class_dev = get_device(csdev); + + /* Note: dev->mutex needs to be unlocked by the caller. */ + return dev; } -void comedi_free_board_minor(unsigned minor) +static void comedi_free_board_minor(unsigned minor) { - unsigned long flags; - struct comedi_device_file_info *info; - BUG_ON(minor >= COMEDI_NUM_BOARD_MINORS); - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - info = comedi_file_info_table[minor]; - comedi_file_info_table[minor] = NULL; - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); - - if (info) { - struct comedi_device *dev = info->device; - if (dev) { - if (dev->class_dev) { - device_destroy(comedi_class, - MKDEV(COMEDI_MAJOR, dev->minor)); - } - comedi_device_cleanup(dev); - kfree(dev); + comedi_free_board_dev(comedi_clear_board_minor(minor)); +} + +void comedi_release_hardware_device(struct device *hardware_device) +{ + int minor; + struct comedi_device *dev; + + for (minor = comedi_num_legacy_minors; minor < COMEDI_NUM_BOARD_MINORS; + minor++) { + mutex_lock(&comedi_board_minor_table_lock); + dev = comedi_board_minor_table[minor]; + if (dev && dev->hw_dev == hardware_device) { + comedi_board_minor_table[minor] = NULL; + mutex_unlock(&comedi_board_minor_table_lock); + comedi_free_board_dev(dev); + break; } - kfree(info); + mutex_unlock(&comedi_board_minor_table_lock); } } -int comedi_alloc_subdevice_minor(struct comedi_device *dev, - struct comedi_subdevice *s) +int comedi_alloc_subdevice_minor(struct comedi_subdevice *s) { - unsigned long flags; - struct comedi_device_file_info *info; + struct comedi_device *dev = s->device; struct device *csdev; unsigned i; - int retval; - info = kmalloc(sizeof(struct comedi_device_file_info), GFP_KERNEL); - if (info == NULL) - return -ENOMEM; - info->device = dev; - info->read_subdevice = s; - info->write_subdevice = s; - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - for (i = COMEDI_FIRST_SUBDEVICE_MINOR; i < COMEDI_NUM_MINORS; ++i) { - if (comedi_file_info_table[i] == NULL) { - comedi_file_info_table[i] = info; + mutex_lock(&comedi_subdevice_minor_table_lock); + for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) { + if (comedi_subdevice_minor_table[i] == NULL) { + comedi_subdevice_minor_table[i] = s; break; } } - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); - if (i == COMEDI_NUM_MINORS) { - kfree(info); - printk(KERN_ERR - "comedi: error: " - "ran out of minor numbers for board device files.\n"); + mutex_unlock(&comedi_subdevice_minor_table_lock); + if (i == COMEDI_NUM_SUBDEVICE_MINORS) { + pr_err("comedi: error: ran out of minor numbers for subdevice files.\n"); return -EBUSY; } + i += COMEDI_NUM_BOARD_MINORS; s->minor = i; - csdev = COMEDI_DEVICE_CREATE(comedi_class, dev->class_dev, - MKDEV(COMEDI_MAJOR, i), NULL, NULL, - "comedi%i_subd%i", dev->minor, - (int)(s - dev->subdevices)); + csdev = device_create(comedi_class, dev->class_dev, + MKDEV(COMEDI_MAJOR, i), NULL, "comedi%i_subd%i", + dev->minor, s->index); if (!IS_ERR(csdev)) s->class_dev = csdev; - dev_set_drvdata(csdev, info); - retval = device_create_file(csdev, &dev_attr_max_read_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_max_read_buffer_kb.attr.name); - comedi_free_subdevice_minor(s); - return retval; - } - retval = device_create_file(csdev, &dev_attr_read_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_read_buffer_kb.attr.name); - comedi_free_subdevice_minor(s); - return retval; - } - retval = device_create_file(csdev, &dev_attr_max_write_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_max_write_buffer_kb.attr.name); - comedi_free_subdevice_minor(s); - return retval; - } - retval = device_create_file(csdev, &dev_attr_write_buffer_kb); - if (retval) { - printk(KERN_ERR - "comedi: " - "failed to create sysfs attribute file \"%s\".\n", - dev_attr_write_buffer_kb.attr.name); - comedi_free_subdevice_minor(s); - return retval; - } - return i; + + return 0; } void comedi_free_subdevice_minor(struct comedi_subdevice *s) { - unsigned long flags; - struct comedi_device_file_info *info; + unsigned int i; if (s == NULL) return; @@ -2333,326 +2556,106 @@ void comedi_free_subdevice_minor(struct comedi_subdevice *s) return; BUG_ON(s->minor >= COMEDI_NUM_MINORS); - BUG_ON(s->minor < COMEDI_FIRST_SUBDEVICE_MINOR); - - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - info = comedi_file_info_table[s->minor]; - comedi_file_info_table[s->minor] = NULL; - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); + BUG_ON(s->minor < COMEDI_NUM_BOARD_MINORS); + i = s->minor - COMEDI_NUM_BOARD_MINORS; + mutex_lock(&comedi_subdevice_minor_table_lock); + if (s == comedi_subdevice_minor_table[i]) + comedi_subdevice_minor_table[i] = NULL; + mutex_unlock(&comedi_subdevice_minor_table_lock); if (s->class_dev) { device_destroy(comedi_class, MKDEV(COMEDI_MAJOR, s->minor)); s->class_dev = NULL; } - kfree(info); -} - -struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor) -{ - unsigned long flags; - struct comedi_device_file_info *info; - - BUG_ON(minor >= COMEDI_NUM_MINORS); - spin_lock_irqsave(&comedi_file_info_table_lock, flags); - info = comedi_file_info_table[minor]; - spin_unlock_irqrestore(&comedi_file_info_table_lock, flags); - return info; -} -EXPORT_SYMBOL_GPL(comedi_get_device_file_info); - -static int resize_async_buffer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_async *async, unsigned new_size) -{ - int retval; - - if (new_size > async->max_bufsize) - return -EPERM; - - if (s->busy) { - DPRINTK("subdevice is busy, cannot resize buffer\n"); - return -EBUSY; - } - if (async->mmap_count) { - DPRINTK("subdevice is mmapped, cannot resize buffer\n"); - return -EBUSY; - } - - if (!async->prealloc_buf) - return -EINVAL; - - /* make sure buffer is an integral number of pages - * (we round up) */ - new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; - - retval = comedi_buf_alloc(dev, s, new_size); - if (retval < 0) - return retval; - - if (s->buf_change) { - retval = s->buf_change(dev, s, new_size); - if (retval < 0) - return retval; - } - - DPRINTK("comedi%i subd %d buffer resized to %i bytes\n", - dev->minor, (int)(s - dev->subdevices), async->prealloc_bufsz); - return 0; } -/* sysfs attribute files */ - -static const unsigned bytes_per_kibi = 1024; - -static ssize_t show_max_read_buffer_kb(struct device *dev, - struct device_attribute *attr, char *buf) +static void comedi_cleanup_board_minors(void) { - ssize_t retval; - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned max_buffer_size_kb = 0; - struct comedi_subdevice *const read_subdevice = - comedi_get_read_subdevice(info); - - mutex_lock(&info->device->mutex); - if (read_subdevice && - (read_subdevice->subdev_flags & SDF_CMD_READ) && - read_subdevice->async) { - max_buffer_size_kb = read_subdevice->async->max_bufsize / - bytes_per_kibi; - } - retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); - mutex_unlock(&info->device->mutex); - - return retval; -} - -static ssize_t store_max_read_buffer_kb(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned long new_max_size_kb; - uint64_t new_max_size; - struct comedi_subdevice *const read_subdevice = - comedi_get_read_subdevice(info); - - if (strict_strtoul(buf, 10, &new_max_size_kb)) - return -EINVAL; - if (new_max_size_kb != (uint32_t) new_max_size_kb) - return -EINVAL; - new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; - if (new_max_size != (uint32_t) new_max_size) - return -EINVAL; - - mutex_lock(&info->device->mutex); - if (read_subdevice == NULL || - (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || - read_subdevice->async == NULL) { - mutex_unlock(&info->device->mutex); - return -EINVAL; - } - read_subdevice->async->max_bufsize = new_max_size; - mutex_unlock(&info->device->mutex); - - return count; -} - -static struct device_attribute dev_attr_max_read_buffer_kb = { - .attr = { - .name = "max_read_buffer_kb", - .mode = S_IRUGO | S_IWUSR}, - .show = &show_max_read_buffer_kb, - .store = &store_max_read_buffer_kb -}; - -static ssize_t show_read_buffer_kb(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned buffer_size_kb = 0; - struct comedi_subdevice *const read_subdevice = - comedi_get_read_subdevice(info); - - mutex_lock(&info->device->mutex); - if (read_subdevice && - (read_subdevice->subdev_flags & SDF_CMD_READ) && - read_subdevice->async) { - buffer_size_kb = read_subdevice->async->prealloc_bufsz / - bytes_per_kibi; - } - retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); - mutex_unlock(&info->device->mutex); + unsigned i; - return retval; + for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) + comedi_free_board_minor(i); } -static ssize_t store_read_buffer_kb(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static int __init comedi_init(void) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned long new_size_kb; - uint64_t new_size; + int i; int retval; - struct comedi_subdevice *const read_subdevice = - comedi_get_read_subdevice(info); - if (strict_strtoul(buf, 10, &new_size_kb)) - return -EINVAL; - if (new_size_kb != (uint32_t) new_size_kb) - return -EINVAL; - new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; - if (new_size != (uint32_t) new_size) - return -EINVAL; + pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n"); - mutex_lock(&info->device->mutex); - if (read_subdevice == NULL || - (read_subdevice->subdev_flags & SDF_CMD_READ) == 0 || - read_subdevice->async == NULL) { - mutex_unlock(&info->device->mutex); + if (comedi_num_legacy_minors < 0 || + comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { + pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n", + COMEDI_NUM_BOARD_MINORS); return -EINVAL; } - retval = resize_async_buffer(info->device, read_subdevice, - read_subdevice->async, new_size); - mutex_unlock(&info->device->mutex); - if (retval < 0) - return retval; - return count; -} - -static struct device_attribute dev_attr_read_buffer_kb = { - .attr = { - .name = "read_buffer_kb", - .mode = S_IRUGO | S_IWUSR | S_IWGRP}, - .show = &show_read_buffer_kb, - .store = &store_read_buffer_kb -}; - -static ssize_t show_max_write_buffer_kb(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - ssize_t retval; - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned max_buffer_size_kb = 0; - struct comedi_subdevice *const write_subdevice = - comedi_get_write_subdevice(info); - - mutex_lock(&info->device->mutex); - if (write_subdevice && - (write_subdevice->subdev_flags & SDF_CMD_WRITE) && - write_subdevice->async) { - max_buffer_size_kb = write_subdevice->async->max_bufsize / - bytes_per_kibi; + retval = register_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS, "comedi"); + if (retval) + return -EIO; + cdev_init(&comedi_cdev, &comedi_fops); + comedi_cdev.owner = THIS_MODULE; + kobject_set_name(&comedi_cdev.kobj, "comedi"); + if (cdev_add(&comedi_cdev, MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS)) { + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return -EIO; } - retval = snprintf(buf, PAGE_SIZE, "%i\n", max_buffer_size_kb); - mutex_unlock(&info->device->mutex); - - return retval; -} - -static ssize_t store_max_write_buffer_kb(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned long new_max_size_kb; - uint64_t new_max_size; - struct comedi_subdevice *const write_subdevice = - comedi_get_write_subdevice(info); - - if (strict_strtoul(buf, 10, &new_max_size_kb)) - return -EINVAL; - if (new_max_size_kb != (uint32_t) new_max_size_kb) - return -EINVAL; - new_max_size = ((uint64_t) new_max_size_kb) * bytes_per_kibi; - if (new_max_size != (uint32_t) new_max_size) - return -EINVAL; - - mutex_lock(&info->device->mutex); - if (write_subdevice == NULL || - (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || - write_subdevice->async == NULL) { - mutex_unlock(&info->device->mutex); - return -EINVAL; + comedi_class = class_create(THIS_MODULE, "comedi"); + if (IS_ERR(comedi_class)) { + pr_err("comedi: failed to create class\n"); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return PTR_ERR(comedi_class); } - write_subdevice->async->max_bufsize = new_max_size; - mutex_unlock(&info->device->mutex); - return count; -} + comedi_class->dev_groups = comedi_dev_groups; -static struct device_attribute dev_attr_max_write_buffer_kb = { - .attr = { - .name = "max_write_buffer_kb", - .mode = S_IRUGO | S_IWUSR}, - .show = &show_max_write_buffer_kb, - .store = &store_max_write_buffer_kb -}; + /* XXX requires /proc interface */ + comedi_proc_init(); -static ssize_t show_write_buffer_kb(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned buffer_size_kb = 0; - struct comedi_subdevice *const write_subdevice = - comedi_get_write_subdevice(info); + /* create devices files for legacy/manual use */ + for (i = 0; i < comedi_num_legacy_minors; i++) { + struct comedi_device *dev; - mutex_lock(&info->device->mutex); - if (write_subdevice && - (write_subdevice->subdev_flags & SDF_CMD_WRITE) && - write_subdevice->async) { - buffer_size_kb = write_subdevice->async->prealloc_bufsz / - bytes_per_kibi; + dev = comedi_alloc_board_minor(NULL); + if (IS_ERR(dev)) { + comedi_cleanup_board_minors(); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), + COMEDI_NUM_MINORS); + return PTR_ERR(dev); + } else { + /* comedi_alloc_board_minor() locked the mutex */ + mutex_unlock(&dev->mutex); + } } - retval = snprintf(buf, PAGE_SIZE, "%i\n", buffer_size_kb); - mutex_unlock(&info->device->mutex); - return retval; + return 0; } +module_init(comedi_init); -static ssize_t store_write_buffer_kb(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static void __exit comedi_cleanup(void) { - struct comedi_device_file_info *info = dev_get_drvdata(dev); - unsigned long new_size_kb; - uint64_t new_size; - int retval; - struct comedi_subdevice *const write_subdevice = - comedi_get_write_subdevice(info); + int i; - if (strict_strtoul(buf, 10, &new_size_kb)) - return -EINVAL; - if (new_size_kb != (uint32_t) new_size_kb) - return -EINVAL; - new_size = ((uint64_t) new_size_kb) * bytes_per_kibi; - if (new_size != (uint32_t) new_size) - return -EINVAL; + comedi_cleanup_board_minors(); + for (i = 0; i < COMEDI_NUM_BOARD_MINORS; ++i) + BUG_ON(comedi_board_minor_table[i]); + for (i = 0; i < COMEDI_NUM_SUBDEVICE_MINORS; ++i) + BUG_ON(comedi_subdevice_minor_table[i]); - mutex_lock(&info->device->mutex); - if (write_subdevice == NULL || - (write_subdevice->subdev_flags & SDF_CMD_WRITE) == 0 || - write_subdevice->async == NULL) { - mutex_unlock(&info->device->mutex); - return -EINVAL; - } - retval = resize_async_buffer(info->device, write_subdevice, - write_subdevice->async, new_size); - mutex_unlock(&info->device->mutex); + class_destroy(comedi_class); + cdev_del(&comedi_cdev); + unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); - if (retval < 0) - return retval; - return count; + comedi_proc_cleanup(); } +module_exit(comedi_cleanup); -static struct device_attribute dev_attr_write_buffer_kb = { - .attr = { - .name = "write_buffer_kb", - .mode = S_IRUGO | S_IWUSR | S_IWGRP}, - .show = &show_write_buffer_kb, - .store = &store_write_buffer_kb -}; +MODULE_AUTHOR("http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi core module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/comedi_fops.h b/drivers/staging/comedi/comedi_fops.h deleted file mode 100644 index da4b4f5553f..00000000000 --- a/drivers/staging/comedi/comedi_fops.h +++ /dev/null @@ -1,10 +0,0 @@ - -#ifndef _COMEDI_FOPS_H -#define _COMEDI_FOPS_H - -extern struct class *comedi_class; -extern const struct file_operations comedi_fops; -extern int comedi_autoconfig; -extern struct comedi_driver *comedi_drivers; - -#endif /* _COMEDI_FOPS_H */ diff --git a/drivers/staging/comedi/comedi_internal.h b/drivers/staging/comedi/comedi_internal.h new file mode 100644 index 00000000000..e978c223f5b --- /dev/null +++ b/drivers/staging/comedi/comedi_internal.h @@ -0,0 +1,56 @@ +#ifndef _COMEDI_INTERNAL_H +#define _COMEDI_INTERNAL_H + +#include <linux/types.h> + +/* + * various internal comedi stuff + */ +int do_rangeinfo_ioctl(struct comedi_device *dev, + struct comedi_rangeinfo __user *arg); +struct comedi_device *comedi_alloc_board_minor(struct device *hardware_device); +void comedi_release_hardware_device(struct device *hardware_device); +int comedi_alloc_subdevice_minor(struct comedi_subdevice *s); +void comedi_free_subdevice_minor(struct comedi_subdevice *s); + +int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned long new_size); +void comedi_buf_reset(struct comedi_subdevice *s); +bool comedi_buf_is_mmapped(struct comedi_subdevice *s); +void comedi_buf_map_get(struct comedi_buf_map *bm); +int comedi_buf_map_put(struct comedi_buf_map *bm); +struct comedi_buf_map *comedi_buf_map_from_subdev_get( + struct comedi_subdevice *s); +unsigned int comedi_buf_write_n_allocated(struct comedi_subdevice *s); +void comedi_device_cancel_all(struct comedi_device *dev); + +extern unsigned int comedi_default_buf_size_kb; +extern unsigned int comedi_default_buf_maxsize_kb; + +/* drivers.c */ + +extern struct comedi_driver *comedi_drivers; +extern struct mutex comedi_drivers_list_lock; + +int insn_inval(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + +void comedi_device_detach(struct comedi_device *); +int comedi_device_attach(struct comedi_device *, struct comedi_devconfig *); + +#ifdef CONFIG_PROC_FS + +/* proc.c */ + +void comedi_proc_init(void); +void comedi_proc_cleanup(void); +#else +static inline void comedi_proc_init(void) +{ +} +static inline void comedi_proc_cleanup(void) +{ +} +#endif + +#endif /* _COMEDI_INTERNAL_H */ diff --git a/drivers/staging/comedi/comedi_pci.c b/drivers/staging/comedi/comedi_pci.c new file mode 100644 index 00000000000..abbc0e4f5c5 --- /dev/null +++ b/drivers/staging/comedi/comedi_pci.c @@ -0,0 +1,146 @@ +/* + * comedi_pci.c + * Comedi PCI driver specific functions. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-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. + */ + +#include <linux/pci.h> + +#include "comedidev.h" + +/** + * comedi_to_pci_dev() - comedi_device pointer to pci_dev pointer. + * @dev: comedi_device struct + */ +struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) +{ + return dev->hw_dev ? to_pci_dev(dev->hw_dev) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_pci_dev); + +/** + * comedi_pci_enable() - Enable the PCI device and request the regions. + * @dev: comedi_device struct + */ +int comedi_pci_enable(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + int rc; + + if (!pcidev) + return -ENODEV; + + rc = pci_enable_device(pcidev); + if (rc < 0) + return rc; + + rc = pci_request_regions(pcidev, dev->board_name); + if (rc < 0) + pci_disable_device(pcidev); + else + dev->ioenabled = true; + + return rc; +} +EXPORT_SYMBOL_GPL(comedi_pci_enable); + +/** + * comedi_pci_disable() - Release the regions and disable the PCI device. + * @dev: comedi_device struct + */ +void comedi_pci_disable(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (pcidev && dev->ioenabled) { + pci_release_regions(pcidev); + pci_disable_device(pcidev); + } + dev->ioenabled = false; +} +EXPORT_SYMBOL_GPL(comedi_pci_disable); + +/** + * comedi_pci_auto_config() - Configure/probe a comedi PCI driver. + * @pcidev: pci_dev struct + * @driver: comedi_driver struct + * @context: driver specific data, passed to comedi_auto_config() + * + * Typically called from the pci_driver (*probe) function. + */ +int comedi_pci_auto_config(struct pci_dev *pcidev, + struct comedi_driver *driver, + unsigned long context) +{ + return comedi_auto_config(&pcidev->dev, driver, context); +} +EXPORT_SYMBOL_GPL(comedi_pci_auto_config); + +/** + * comedi_pci_auto_unconfig() - Unconfigure/remove a comedi PCI driver. + * @pcidev: pci_dev struct + * + * Typically called from the pci_driver (*remove) function. + */ +void comedi_pci_auto_unconfig(struct pci_dev *pcidev) +{ + comedi_auto_unconfig(&pcidev->dev); +} +EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); + +/** + * comedi_pci_driver_register() - Register a comedi PCI driver. + * @comedi_driver: comedi_driver struct + * @pci_driver: pci_driver struct + * + * This function is used for the module_init() of comedi PCI drivers. + * Do not call it directly, use the module_comedi_pci_driver() helper + * macro instead. + */ +int comedi_pci_driver_register(struct comedi_driver *comedi_driver, + struct pci_driver *pci_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + ret = pci_register_driver(pci_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_pci_driver_register); + +/** + * comedi_pci_driver_unregister() - Unregister a comedi PCI driver. + * @comedi_driver: comedi_driver struct + * @pci_driver: pci_driver struct + * + * This function is used for the module_exit() of comedi PCI drivers. + * Do not call it directly, use the module_comedi_pci_driver() helper + * macro instead. + */ +void comedi_pci_driver_unregister(struct comedi_driver *comedi_driver, + struct pci_driver *pci_driver) +{ + pci_unregister_driver(pci_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_pci_driver_unregister); diff --git a/drivers/staging/comedi/comedi_pcmcia.c b/drivers/staging/comedi/comedi_pcmcia.c new file mode 100644 index 00000000000..9d49d5d01ad --- /dev/null +++ b/drivers/staging/comedi/comedi_pcmcia.c @@ -0,0 +1,156 @@ +/* + * comedi_pcmcia.c + * Comedi PCMCIA driver specific functions. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-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. + */ + +#include <linux/kernel.h> + +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> + +#include "comedidev.h" + +/** + * comedi_to_pcmcia_dev() - comedi_device pointer to pcmcia_device pointer. + * @dev: comedi_device struct + */ +struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *dev) +{ + return dev->hw_dev ? to_pcmcia_dev(dev->hw_dev) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_pcmcia_dev); + +static int comedi_pcmcia_conf_check(struct pcmcia_device *link, + void *priv_data) +{ + if (link->config_index == 0) + return -EINVAL; + + return pcmcia_request_io(link); +} + +/** + * comedi_pcmcia_enable() - Request the regions and enable the PCMCIA device. + * @dev: comedi_device struct + * @conf_check: optional callback to check the pcmcia_device configuration + * + * The comedi PCMCIA driver needs to set the link->config_flags, as + * appropriate for that driver, before calling this function in order + * to allow pcmcia_loop_config() to do its internal autoconfiguration. + */ +int comedi_pcmcia_enable(struct comedi_device *dev, + int (*conf_check)(struct pcmcia_device *, void *)) +{ + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + int ret; + + if (!link) + return -ENODEV; + + if (!conf_check) + conf_check = comedi_pcmcia_conf_check; + + ret = pcmcia_loop_config(link, conf_check, NULL); + if (ret) + return ret; + + return pcmcia_enable_device(link); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_enable); + +/** + * comedi_pcmcia_disable() - Disable the PCMCIA device and release the regions. + * @dev: comedi_device struct + */ +void comedi_pcmcia_disable(struct comedi_device *dev) +{ + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + + if (link) + pcmcia_disable_device(link); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_disable); + +/** + * comedi_pcmcia_auto_config() - Configure/probe a comedi PCMCIA driver. + * @link: pcmcia_device struct + * @driver: comedi_driver struct + * + * Typically called from the pcmcia_driver (*probe) function. + */ +int comedi_pcmcia_auto_config(struct pcmcia_device *link, + struct comedi_driver *driver) +{ + return comedi_auto_config(&link->dev, driver, 0); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_config); + +/** + * comedi_pcmcia_auto_unconfig() - Unconfigure/remove a comedi PCMCIA driver. + * @link: pcmcia_device struct + * + * Typically called from the pcmcia_driver (*remove) function. + */ +void comedi_pcmcia_auto_unconfig(struct pcmcia_device *link) +{ + comedi_auto_unconfig(&link->dev); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_auto_unconfig); + +/** + * comedi_pcmcia_driver_register() - Register a comedi PCMCIA driver. + * @comedi_driver: comedi_driver struct + * @pcmcia_driver: pcmcia_driver struct + * + * This function is used for the module_init() of comedi USB drivers. + * Do not call it directly, use the module_comedi_pcmcia_driver() helper + * macro instead. + */ +int comedi_pcmcia_driver_register(struct comedi_driver *comedi_driver, + struct pcmcia_driver *pcmcia_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + ret = pcmcia_register_driver(pcmcia_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_register); + +/** + * comedi_pcmcia_driver_unregister() - Unregister a comedi PCMCIA driver. + * @comedi_driver: comedi_driver struct + * @pcmcia_driver: pcmcia_driver struct + * + * This function is used for the module_exit() of comedi PCMCIA drivers. + * Do not call it directly, use the module_comedi_pcmcia_driver() helper + * macro instead. + */ +void comedi_pcmcia_driver_unregister(struct comedi_driver *comedi_driver, + struct pcmcia_driver *pcmcia_driver) +{ + pcmcia_unregister_driver(pcmcia_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_pcmcia_driver_unregister); diff --git a/drivers/staging/comedi/comedi_usb.c b/drivers/staging/comedi/comedi_usb.c new file mode 100644 index 00000000000..13f18bef609 --- /dev/null +++ b/drivers/staging/comedi/comedi_usb.c @@ -0,0 +1,116 @@ +/* + * comedi_usb.c + * Comedi USB driver specific functions. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-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. + */ + +#include <linux/usb.h> + +#include "comedidev.h" + +/** + * comedi_to_usb_interface() - comedi_device pointer to usb_interface pointer. + * @dev: comedi_device struct + */ +struct usb_interface *comedi_to_usb_interface(struct comedi_device *dev) +{ + return dev->hw_dev ? to_usb_interface(dev->hw_dev) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_usb_interface); + +/** + * comedi_to_usb_dev() - comedi_device pointer to usb_device pointer. + * @dev: comedi_device struct + */ +struct usb_device *comedi_to_usb_dev(struct comedi_device *dev) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + + return intf ? interface_to_usbdev(intf) : NULL; +} +EXPORT_SYMBOL_GPL(comedi_to_usb_dev); + +/** + * comedi_usb_auto_config() - Configure/probe a comedi USB driver. + * @intf: usb_interface struct + * @driver: comedi_driver struct + * @context: driver specific data, passed to comedi_auto_config() + * + * Typically called from the usb_driver (*probe) function. + */ +int comedi_usb_auto_config(struct usb_interface *intf, + struct comedi_driver *driver, + unsigned long context) +{ + return comedi_auto_config(&intf->dev, driver, context); +} +EXPORT_SYMBOL_GPL(comedi_usb_auto_config); + +/** + * comedi_pci_auto_unconfig() - Unconfigure/disconnect a comedi USB driver. + * @intf: usb_interface struct + * + * Typically called from the usb_driver (*disconnect) function. + */ +void comedi_usb_auto_unconfig(struct usb_interface *intf) +{ + comedi_auto_unconfig(&intf->dev); +} +EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig); + +/** + * comedi_usb_driver_register() - Register a comedi USB driver. + * @comedi_driver: comedi_driver struct + * @usb_driver: usb_driver struct + * + * This function is used for the module_init() of comedi USB drivers. + * Do not call it directly, use the module_comedi_usb_driver() helper + * macro instead. + */ +int comedi_usb_driver_register(struct comedi_driver *comedi_driver, + struct usb_driver *usb_driver) +{ + int ret; + + ret = comedi_driver_register(comedi_driver); + if (ret < 0) + return ret; + + ret = usb_register(usb_driver); + if (ret < 0) { + comedi_driver_unregister(comedi_driver); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(comedi_usb_driver_register); + +/** + * comedi_usb_driver_unregister() - Unregister a comedi USB driver. + * @comedi_driver: comedi_driver struct + * @usb_driver: usb_driver struct + * + * This function is used for the module_exit() of comedi USB drivers. + * Do not call it directly, use the module_comedi_usb_driver() helper + * macro instead. + */ +void comedi_usb_driver_unregister(struct comedi_driver *comedi_driver, + struct usb_driver *usb_driver) +{ + usb_deregister(usb_driver); + comedi_driver_unregister(comedi_driver); +} +EXPORT_SYMBOL_GPL(comedi_usb_driver_unregister); diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index 68aa9176d24..8f4e44bfbe0 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -14,58 +14,29 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDIDEV_H #define _COMEDIDEV_H -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/kdev_t.h> -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/spinlock.h> -#include <linux/mutex.h> -#include <linux/wait.h> -#include <linux/mm.h> -#include <linux/init.h> -#include <linux/vmalloc.h> #include <linux/dma-mapping.h> -#include <linux/uaccess.h> -#include <linux/io.h> -#include <linux/timer.h> +#include <linux/mutex.h> +#include <linux/spinlock_types.h> +#include <linux/rwsem.h> +#include <linux/kref.h> #include "comedi.h" -#define DPRINTK(format, args...) do { \ - if (comedi_debug) \ - printk(KERN_DEBUG "comedi: " format , ## args); \ -} while (0) - #define COMEDI_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) #define COMEDI_VERSION_CODE COMEDI_VERSION(COMEDI_MAJORVERSION, \ COMEDI_MINORVERSION, COMEDI_MICROVERSION) #define COMEDI_RELEASE VERSION -#define PCI_VENDOR_ID_ADLINK 0x144a -#define PCI_VENDOR_ID_ICP 0x104c -#define PCI_VENDOR_ID_CONTEC 0x1221 - -#define COMEDI_NUM_MINORS 0x100 #define COMEDI_NUM_BOARD_MINORS 0x30 -#define COMEDI_FIRST_SUBDEVICE_MINOR COMEDI_NUM_BOARD_MINORS - -#define COMEDI_DEVICE_CREATE(cs, parent, devt, drvdata, device, fmt...) \ - device_create(cs, ((parent) ? (parent) : (device)), devt, drvdata, fmt) struct comedi_subdevice { struct comedi_device *device; + int index; int type; int n_chan; int subdev_flags; @@ -80,46 +51,41 @@ struct comedi_subdevice { unsigned runflags; spinlock_t spin_lock; - int io_bits; + unsigned int io_bits; unsigned int maxdata; /* if maxdata==0, use list */ const unsigned int *maxdata_list; /* list is channel specific */ - unsigned int flags; - const unsigned int *flaglist; - - unsigned int settling_time_0; - const struct comedi_lrange *range_table; const struct comedi_lrange *const *range_table_list; unsigned int *chanlist; /* driver-owned chanlist (not used) */ - int (*insn_read) (struct comedi_device *, struct comedi_subdevice *, + int (*insn_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*insn_write)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*insn_write) (struct comedi_device *, struct comedi_subdevice *, + int (*insn_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*insn_config)(struct comedi_device *, struct comedi_subdevice *, struct comedi_insn *, unsigned int *); - int (*insn_bits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insn_config) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - - int (*do_cmd) (struct comedi_device *, struct comedi_subdevice *); - int (*do_cmdtest) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_cmd *); - int (*poll) (struct comedi_device *, struct comedi_subdevice *); - int (*cancel) (struct comedi_device *, struct comedi_subdevice *); + + int (*do_cmd)(struct comedi_device *, struct comedi_subdevice *); + int (*do_cmdtest)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_cmd *); + int (*poll)(struct comedi_device *, struct comedi_subdevice *); + int (*cancel)(struct comedi_device *, struct comedi_subdevice *); /* int (*do_lock)(struct comedi_device *, struct comedi_subdevice *); */ /* int (*do_unlock)(struct comedi_device *, \ struct comedi_subdevice *); */ /* called when the buffer changes */ - int (*buf_change) (struct comedi_device *dev, - struct comedi_subdevice *s, unsigned long new_size); + int (*buf_change)(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned long new_size); - void (*munge) (struct comedi_device *dev, struct comedi_subdevice *s, - void *data, unsigned int num_bytes, - unsigned int start_chan_index); + void (*munge)(struct comedi_device *dev, struct comedi_subdevice *s, + void *data, unsigned int num_bytes, + unsigned int start_chan_index); enum dma_data_direction async_dma_dir; unsigned int state; @@ -133,18 +99,20 @@ struct comedi_buf_page { dma_addr_t dma_addr; }; -struct comedi_async { - struct comedi_subdevice *subdevice; +struct comedi_buf_map { + struct device *dma_hw_dev; + struct comedi_buf_page *page_list; + unsigned int n_pages; + enum dma_data_direction dma_dir; + struct kref refcount; +}; +struct comedi_async { void *prealloc_buf; /* pre-allocated buffer */ unsigned int prealloc_bufsz; /* buffer size, in bytes */ - /* virtual and dma address of each page */ - struct comedi_buf_page *buf_page_list; - unsigned n_buf_pages; /* num elements in buf_page_list */ + struct comedi_buf_map *buf_map; /* map of buffer pages */ unsigned int max_bufsize; /* maximum buffer size, bytes */ - /* current number of mmaps of prealloc_buf */ - unsigned int mmap_count; /* byte count for writer (write completed) */ unsigned int buf_write_count; @@ -174,13 +142,10 @@ struct comedi_async { wait_queue_head_t wait_head; - /* callback stuff */ unsigned int cb_mask; - int (*cb_func) (unsigned int flags, void *); - void *cb_arg; - int (*inttrig) (struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int x); + int (*inttrig)(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned int x); }; struct comedi_driver { @@ -188,8 +153,9 @@ struct comedi_driver { const char *driver_name; struct module *module; - int (*attach) (struct comedi_device *, struct comedi_devconfig *); - int (*detach) (struct comedi_device *); + int (*attach)(struct comedi_device *, struct comedi_devconfig *); + void (*detach)(struct comedi_device *); + int (*auto_attach)(struct comedi_device *, unsigned long); /* number of elements in board_name and board_id arrays */ unsigned int num_names; @@ -205,6 +171,7 @@ struct comedi_device { struct device *class_dev; int minor; + unsigned int detach_count; /* hw_dev is passed to dma_alloc_coherent when allocating async buffers * for subdevices that have async_dma_dir set to something other than * DMA_NONE */ @@ -212,16 +179,19 @@ struct comedi_device { const char *board_name; const void *board_ptr; - int attached; + bool attached:1; + bool ioenabled:1; spinlock_t spinlock; struct mutex mutex; - int in_request_module; + struct rw_semaphore attach_lock; + struct kref refcount; int n_subdevices; struct comedi_subdevice *subdevices; /* dumb */ unsigned long iobase; + unsigned long iolen; unsigned int irq; struct comedi_subdevice *read_subdev; @@ -229,21 +199,14 @@ struct comedi_device { struct fasync_struct *async_queue; - int (*open) (struct comedi_device *dev); - void (*close) (struct comedi_device *dev); + int (*open)(struct comedi_device *dev); + void (*close)(struct comedi_device *dev); }; -struct comedi_device_file_info { - struct comedi_device *device; - struct comedi_subdevice *read_subdevice; - struct comedi_subdevice *write_subdevice; -}; - -#ifdef CONFIG_COMEDI_DEBUG -extern int comedi_debug; -#else -static const int comedi_debug; -#endif +static inline const void *comedi_board(const struct comedi_device *dev) +{ + return dev->board_ptr; +} /* * function prototypes @@ -262,66 +225,31 @@ enum comedi_minor_bits { static const unsigned COMEDI_SUBDEVICE_MINOR_SHIFT = 4; static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1; -struct comedi_device_file_info *comedi_get_device_file_info(unsigned minor); - -static inline struct comedi_subdevice *comedi_get_read_subdevice( - const struct comedi_device_file_info *info) -{ - if (info->read_subdevice) - return info->read_subdevice; - if (info->device == NULL) - return NULL; - return info->device->read_subdev; -} - -static inline struct comedi_subdevice *comedi_get_write_subdevice( - const struct comedi_device_file_info *info) -{ - if (info->write_subdevice) - return info->write_subdevice; - if (info->device == NULL) - return NULL; - return info->device->write_subdev; -} - -void comedi_device_detach(struct comedi_device *dev); -int comedi_device_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -int comedi_driver_register(struct comedi_driver *); -int comedi_driver_unregister(struct comedi_driver *); +struct comedi_device *comedi_dev_get_from_minor(unsigned minor); +int comedi_dev_put(struct comedi_device *dev); void init_polling(void); void cleanup_polling(void); void start_polling(struct comedi_device *); void stop_polling(struct comedi_device *); -#ifdef CONFIG_PROC_FS -void comedi_proc_init(void); -void comedi_proc_cleanup(void); -#else -static inline void comedi_proc_init(void) -{ -} - -static inline void comedi_proc_cleanup(void) -{ -} -#endif - /* subdevice runflags */ enum subdevice_runflags { - SRF_USER = 0x00000001, SRF_RT = 0x00000002, /* indicates an COMEDI_CB_ERROR event has occurred since the last * command was started */ SRF_ERROR = 0x00000004, - SRF_RUNNING = 0x08000000 + SRF_RUNNING = 0x08000000, + SRF_FREE_SPRIV = 0x80000000, /* free s->private on detach */ }; +bool comedi_is_subdevice_running(struct comedi_subdevice *s); + +void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size); + int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist); -unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s); /* range stuff */ @@ -337,6 +265,10 @@ extern const struct comedi_lrange range_bipolar5; extern const struct comedi_lrange range_bipolar2_5; extern const struct comedi_lrange range_unipolar10; extern const struct comedi_lrange range_unipolar5; +extern const struct comedi_lrange range_unipolar2_5; +extern const struct comedi_lrange range_0_20mA; +extern const struct comedi_lrange range_4_20mA; +extern const struct comedi_lrange range_0_32mA; extern const struct comedi_lrange range_unknown; #define range_digital range_unipolar5 @@ -352,34 +284,37 @@ struct comedi_lrange { struct comedi_krange range[GCC_ZERO_LENGTH_ARRAY]; }; -/* some silly little inline functions */ +static inline bool comedi_range_is_bipolar(struct comedi_subdevice *s, + unsigned int range) +{ + return s->range_table->range[range].min < 0; +} + +static inline bool comedi_range_is_unipolar(struct comedi_subdevice *s, + unsigned int range) +{ + return s->range_table->range[range].min >= 0; +} + +static inline bool comedi_chan_range_is_bipolar(struct comedi_subdevice *s, + unsigned int chan, + unsigned int range) +{ + return s->range_table_list[chan]->range[range].min < 0; +} -static inline int alloc_subdevices(struct comedi_device *dev, - unsigned int num_subdevices) +static inline bool comedi_chan_range_is_unipolar(struct comedi_subdevice *s, + unsigned int chan, + unsigned int range) { - unsigned i; - - dev->n_subdevices = num_subdevices; - dev->subdevices = - kcalloc(num_subdevices, sizeof(struct comedi_subdevice), - GFP_KERNEL); - if (!dev->subdevices) - return -ENOMEM; - for (i = 0; i < num_subdevices; ++i) { - dev->subdevices[i].device = dev; - dev->subdevices[i].async_dma_dir = DMA_NONE; - spin_lock_init(&dev->subdevices[i].spin_lock); - dev->subdevices[i].minor = -1; - } - return 0; + return s->range_table_list[chan]->range[range].min >= 0; } -static inline int alloc_private(struct comedi_device *dev, int size) +/* munge between offset binary and two's complement values */ +static inline unsigned int comedi_offset_munge(struct comedi_subdevice *s, + unsigned int val) { - dev->private = kzalloc(size, GFP_KERNEL); - if (!dev->private) - return -ENOMEM; - return 0; + return val ^ s->maxdata ^ (s->maxdata >> 1); } static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd) @@ -390,92 +325,216 @@ static inline unsigned int bytes_per_sample(const struct comedi_subdevice *subd) return sizeof(short); } -/* must be used in attach to set dev->hw_dev if you wish to dma directly -into comedi's buffer */ -static inline void comedi_set_hw_dev(struct comedi_device *dev, - struct device *hw_dev) -{ - if (dev->hw_dev) - put_device(dev->hw_dev); - - dev->hw_dev = hw_dev; - if (dev->hw_dev) { - dev->hw_dev = get_device(dev->hw_dev); - BUG_ON(dev->hw_dev == NULL); - } -} +/* + * Must set dev->hw_dev if you wish to dma directly into comedi's buffer. + * Also useful for retrieving a previously configured hardware device of + * known bus type. Set automatically for auto-configured devices. + * Automatically set to NULL when detaching hardware device. + */ +int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev); + +unsigned int comedi_buf_write_alloc(struct comedi_subdevice *s, unsigned int n); +unsigned int comedi_buf_write_free(struct comedi_subdevice *s, unsigned int n); + +unsigned int comedi_buf_read_n_available(struct comedi_subdevice *s); +unsigned int comedi_buf_read_alloc(struct comedi_subdevice *s, unsigned int n); +unsigned int comedi_buf_read_free(struct comedi_subdevice *s, unsigned int n); + +int comedi_buf_put(struct comedi_subdevice *s, unsigned short x); +int comedi_buf_get(struct comedi_subdevice *s, unsigned short *x); -int comedi_buf_put(struct comedi_async *async, short x); -int comedi_buf_get(struct comedi_async *async, short *x); - -unsigned int comedi_buf_write_n_available(struct comedi_async *async); -unsigned int comedi_buf_write_alloc(struct comedi_async *async, - unsigned int nbytes); -unsigned int comedi_buf_write_alloc_strict(struct comedi_async *async, - unsigned int nbytes); -unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes); -unsigned comedi_buf_read_alloc(struct comedi_async *async, unsigned nbytes); -unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes); -unsigned int comedi_buf_read_n_available(struct comedi_async *async); -void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, +void comedi_buf_memcpy_to(struct comedi_subdevice *s, unsigned int offset, const void *source, unsigned int num_bytes); -void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, +void comedi_buf_memcpy_from(struct comedi_subdevice *s, unsigned int offset, void *destination, unsigned int num_bytes); -static inline unsigned comedi_buf_write_n_allocated(struct comedi_async *async) + +/* drivers.c - general comedi driver functions */ + +#define COMEDI_TIMEOUT_MS 1000 + +int comedi_timeout(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, + int (*cb)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned long context), + unsigned long context); + +int comedi_dio_insn_config(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *data, + unsigned int mask); +unsigned int comedi_dio_update_state(struct comedi_subdevice *, + unsigned int *data); + +void *comedi_alloc_devpriv(struct comedi_device *, size_t); +int comedi_alloc_subdevices(struct comedi_device *, int); + +int comedi_load_firmware(struct comedi_device *, struct device *, + const char *name, + int (*cb)(struct comedi_device *, + const u8 *data, size_t size, + unsigned long context), + unsigned long context); + +int __comedi_request_region(struct comedi_device *, + unsigned long start, unsigned long len); +int comedi_request_region(struct comedi_device *, + unsigned long start, unsigned long len); +void comedi_legacy_detach(struct comedi_device *); + +int comedi_auto_config(struct device *, struct comedi_driver *, + unsigned long context); +void comedi_auto_unconfig(struct device *); + +int comedi_driver_register(struct comedi_driver *); +void comedi_driver_unregister(struct comedi_driver *); + +/** + * module_comedi_driver() - Helper macro for registering a comedi driver + * @__comedi_driver: comedi_driver struct + * + * Helper macro for comedi drivers which do not do anything special in module + * init/exit. This eliminates a lot of boilerplate. Each module may only use + * this macro once, and calling it replaces module_init() and module_exit(). + */ +#define module_comedi_driver(__comedi_driver) \ + module_driver(__comedi_driver, comedi_driver_register, \ + comedi_driver_unregister) + +#ifdef CONFIG_COMEDI_PCI_DRIVERS + +/* comedi_pci.c - comedi PCI driver specific functions */ + +/* + * PCI Vendor IDs not in <linux/pci_ids.h> + */ +#define PCI_VENDOR_ID_KOLTER 0x1001 +#define PCI_VENDOR_ID_ICP 0x104c +#define PCI_VENDOR_ID_DT 0x1116 +#define PCI_VENDOR_ID_IOTECH 0x1616 +#define PCI_VENDOR_ID_CONTEC 0x1221 +#define PCI_VENDOR_ID_RTD 0x1435 +#define PCI_VENDOR_ID_HUMUSOFT 0x186c + +struct pci_dev; +struct pci_driver; + +struct pci_dev *comedi_to_pci_dev(struct comedi_device *); + +int comedi_pci_enable(struct comedi_device *); +void comedi_pci_disable(struct comedi_device *); + +int comedi_pci_auto_config(struct pci_dev *, struct comedi_driver *, + unsigned long context); +void comedi_pci_auto_unconfig(struct pci_dev *); + +int comedi_pci_driver_register(struct comedi_driver *, struct pci_driver *); +void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *); + +/** + * module_comedi_pci_driver() - Helper macro for registering a comedi PCI driver + * @__comedi_driver: comedi_driver struct + * @__pci_driver: pci_driver struct + * + * Helper macro for comedi PCI drivers which do not do anything special + * in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces + * module_init() and module_exit() + */ +#define module_comedi_pci_driver(__comedi_driver, __pci_driver) \ + module_driver(__comedi_driver, comedi_pci_driver_register, \ + comedi_pci_driver_unregister, &(__pci_driver)) + +#else + +/* + * Some of the comedi mixed ISA/PCI drivers call the PCI specific + * functions. Provide some dummy functions if CONFIG_COMEDI_PCI_DRIVERS + * is not enabled. + */ + +static inline struct pci_dev *comedi_to_pci_dev(struct comedi_device *dev) { - return async->buf_write_alloc_count - async->buf_write_count; + return NULL; } -static inline unsigned comedi_buf_read_n_allocated(struct comedi_async *async) +static inline int comedi_pci_enable(struct comedi_device *dev) { - return async->buf_read_alloc_count - async->buf_read_count; + return -ENOSYS; } -static inline void *comedi_aux_data(int options[], int n) +static inline void comedi_pci_disable(struct comedi_device *dev) { - unsigned long address; - unsigned long addressLow; - int bit_shift; - if (sizeof(int) >= sizeof(void *)) - address = options[COMEDI_DEVCONF_AUX_DATA_LO]; - else { - address = options[COMEDI_DEVCONF_AUX_DATA_HI]; - bit_shift = sizeof(int) * 8; - address <<= bit_shift; - addressLow = options[COMEDI_DEVCONF_AUX_DATA_LO]; - addressLow &= (1UL << bit_shift) - 1; - address |= addressLow; - } - if (n >= 1) - address += options[COMEDI_DEVCONF_AUX_DATA0_LENGTH]; - if (n >= 2) - address += options[COMEDI_DEVCONF_AUX_DATA1_LENGTH]; - if (n >= 3) - address += options[COMEDI_DEVCONF_AUX_DATA2_LENGTH]; - BUG_ON(n > 3); - return (void *)address; } -int comedi_alloc_subdevice_minor(struct comedi_device *dev, - struct comedi_subdevice *s); -void comedi_free_subdevice_minor(struct comedi_subdevice *s); -int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name); -void comedi_pci_auto_unconfig(struct pci_dev *pcidev); -struct usb_device; /* forward declaration */ -int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name); -void comedi_usb_auto_unconfig(struct usb_device *usbdev); +#endif /* CONFIG_COMEDI_PCI_DRIVERS */ -#ifdef CONFIG_COMEDI_PCI_DRIVERS -#define CONFIG_COMEDI_PCI -#endif -#ifdef CONFIG_COMEDI_PCI_DRIVERS_MODULE -#define CONFIG_COMEDI_PCI -#endif #ifdef CONFIG_COMEDI_PCMCIA_DRIVERS -#define CONFIG_COMEDI_PCMCIA -#endif -#ifdef CONFIG_COMEDI_PCMCIA_DRIVERS_MODULE -#define CONFIG_COMEDI_PCMCIA -#endif + +/* comedi_pcmcia.c - comedi PCMCIA driver specific functions */ + +struct pcmcia_driver; +struct pcmcia_device; + +struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *); + +int comedi_pcmcia_enable(struct comedi_device *, + int (*conf_check)(struct pcmcia_device *, void *)); +void comedi_pcmcia_disable(struct comedi_device *); + +int comedi_pcmcia_auto_config(struct pcmcia_device *, struct comedi_driver *); +void comedi_pcmcia_auto_unconfig(struct pcmcia_device *); + +int comedi_pcmcia_driver_register(struct comedi_driver *, + struct pcmcia_driver *); +void comedi_pcmcia_driver_unregister(struct comedi_driver *, + struct pcmcia_driver *); + +/** + * module_comedi_pcmcia_driver() - Helper macro for registering a comedi PCMCIA driver + * @__comedi_driver: comedi_driver struct + * @__pcmcia_driver: pcmcia_driver struct + * + * Helper macro for comedi PCMCIA drivers which do not do anything special + * in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces + * module_init() and module_exit() + */ +#define module_comedi_pcmcia_driver(__comedi_driver, __pcmcia_driver) \ + module_driver(__comedi_driver, comedi_pcmcia_driver_register, \ + comedi_pcmcia_driver_unregister, &(__pcmcia_driver)) + +#endif /* CONFIG_COMEDI_PCMCIA_DRIVERS */ + +#ifdef CONFIG_COMEDI_USB_DRIVERS + +/* comedi_usb.c - comedi USB driver specific functions */ + +struct usb_driver; +struct usb_interface; + +struct usb_interface *comedi_to_usb_interface(struct comedi_device *); +struct usb_device *comedi_to_usb_dev(struct comedi_device *); + +int comedi_usb_auto_config(struct usb_interface *, struct comedi_driver *, + unsigned long context); +void comedi_usb_auto_unconfig(struct usb_interface *); + +int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *); +void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *); + +/** + * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver + * @__comedi_driver: comedi_driver struct + * @__usb_driver: usb_driver struct + * + * Helper macro for comedi USB drivers which do not do anything special + * in module init/exit. This eliminates a lot of boilerplate. Each + * module may only use this macro once, and calling it replaces + * module_init() and module_exit() + */ +#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \ + module_driver(__comedi_driver, comedi_usb_driver_register, \ + comedi_usb_driver_unregister, &(__usb_driver)) + +#endif /* CONFIG_COMEDI_USB_DRIVERS */ #endif /* _COMEDIDEV_H */ diff --git a/drivers/staging/comedi/comedilib.h b/drivers/staging/comedi/comedilib.h index ca92c43fdb3..56baf852ecf 100644 --- a/drivers/staging/comedi/comedilib.h +++ b/drivers/staging/comedi/comedilib.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _LINUX_COMEDILIB_H @@ -26,10 +21,13 @@ struct comedi_device *comedi_open(const char *path); int comedi_close(struct comedi_device *dev); +int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev, + unsigned int chan, unsigned int *io); int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, unsigned int chan, unsigned int io); -int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev, - unsigned int mask, unsigned int *bits); +int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev, + unsigned int mask, unsigned int *bits, + unsigned int base_channel); int comedi_find_subdevice_by_type(struct comedi_device *dev, int type, unsigned int subd); int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice); diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 6d60e91b3a8..299726f39e2 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -14,26 +14,15 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#define _GNU_SOURCE - -#define __NO_VERSION__ -#include "comedi_fops.h" #include <linux/device.h> #include <linux/module.h> -#include <linux/pci.h> -#include <linux/usb.h> #include <linux/errno.h> +#include <linux/kconfig.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/fcntl.h> -#include <linux/delay.h> #include <linux/ioport.h> #include <linux/mm.h> #include <linux/slab.h> @@ -42,29 +31,80 @@ #include <linux/cdev.h> #include <linux/dma-mapping.h> #include <linux/io.h> -#include <asm/system.h> +#include <linux/interrupt.h> +#include <linux/firmware.h> #include "comedidev.h" -#include "internal.h" - -static int postconfig(struct comedi_device *dev); -static int insn_rw_emulate_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static void *comedi_recognize(struct comedi_driver *driv, const char *name); -static void comedi_report_boards(struct comedi_driver *driv); -static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s); +#include "comedi_internal.h" struct comedi_driver *comedi_drivers; +DEFINE_MUTEX(comedi_drivers_list_lock); + +int comedi_set_hw_dev(struct comedi_device *dev, struct device *hw_dev) +{ + if (hw_dev == dev->hw_dev) + return 0; + if (dev->hw_dev != NULL) + return -EEXIST; + dev->hw_dev = get_device(hw_dev); + return 0; +} +EXPORT_SYMBOL_GPL(comedi_set_hw_dev); + +static void comedi_clear_hw_dev(struct comedi_device *dev) +{ + put_device(dev->hw_dev); + dev->hw_dev = NULL; +} + +/** + * comedi_alloc_devpriv() - Allocate memory for the device private data. + * @dev: comedi_device struct + * @size: size of the memory to allocate + */ +void *comedi_alloc_devpriv(struct comedi_device *dev, size_t size) +{ + dev->private = kzalloc(size, GFP_KERNEL); + return dev->private; +} +EXPORT_SYMBOL_GPL(comedi_alloc_devpriv); + +int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) +{ + struct comedi_subdevice *s; + int i; -static void cleanup_device(struct comedi_device *dev) + if (num_subdevices < 1) + return -EINVAL; + + s = kcalloc(num_subdevices, sizeof(*s), GFP_KERNEL); + if (!s) + return -ENOMEM; + dev->subdevices = s; + dev->n_subdevices = num_subdevices; + + for (i = 0; i < num_subdevices; ++i) { + s = &dev->subdevices[i]; + s->device = dev; + s->index = i; + s->async_dma_dir = DMA_NONE; + spin_lock_init(&s->spin_lock); + s->minor = -1; + } + return 0; +} +EXPORT_SYMBOL_GPL(comedi_alloc_subdevices); + +static void comedi_device_detach_cleanup(struct comedi_device *dev) { int i; struct comedi_subdevice *s; if (dev->subdevices) { for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; + if (s->runflags & SRF_FREE_SPRIV) + kfree(s->private); comedi_free_subdevice_minor(s); if (s->async) { comedi_buf_alloc(dev, s, 0); @@ -81,200 +121,240 @@ static void cleanup_device(struct comedi_device *dev) dev->board_name = NULL; dev->board_ptr = NULL; dev->iobase = 0; + dev->iolen = 0; + dev->ioenabled = false; dev->irq = 0; dev->read_subdev = NULL; dev->write_subdev = NULL; dev->open = NULL; dev->close = NULL; - comedi_set_hw_dev(dev, NULL); + comedi_clear_hw_dev(dev); } -static void __comedi_device_detach(struct comedi_device *dev) +void comedi_device_detach(struct comedi_device *dev) { - dev->attached = 0; + comedi_device_cancel_all(dev); + down_write(&dev->attach_lock); + dev->attached = false; + dev->detach_count++; if (dev->driver) dev->driver->detach(dev); - else - printk(KERN_WARNING - "BUG: dev->driver=NULL in comedi_device_detach()\n"); - cleanup_device(dev); + comedi_device_detach_cleanup(dev); + up_write(&dev->attach_lock); } -void comedi_device_detach(struct comedi_device *dev) +static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s) { - if (!dev->attached) - return; - __comedi_device_detach(dev); + return -EINVAL; } -int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) +int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - struct comedi_driver *driv; - int ret; - - if (dev->attached) - return -EBUSY; - - for (driv = comedi_drivers; driv; driv = driv->next) { - if (!try_module_get(driv->module)) { - printk(KERN_INFO "comedi: failed to increment module count, skipping\n"); - continue; - } - if (driv->num_names) { - dev->board_ptr = comedi_recognize(driv, it->board_name); - if (dev->board_ptr == NULL) { - module_put(driv->module); - continue; - } - } else { - if (strcmp(driv->driver_name, it->board_name)) { - module_put(driv->module); - continue; - } - } - /* initialize dev->driver here so - * comedi_error() can be called from attach */ - dev->driver = driv; - ret = driv->attach(dev, it); - if (ret < 0) { - module_put(dev->driver->module); - __comedi_device_detach(dev); - return ret; - } - goto attached; - } + return -EINVAL; +} - /* recognize has failed if we get here */ - /* report valid board names before returning error */ - for (driv = comedi_drivers; driv; driv = driv->next) { - if (!try_module_get(driv->module)) { - printk(KERN_INFO - "comedi: failed to increment module count\n"); - continue; - } - comedi_report_boards(driv); - module_put(driv->module); - } - return -EIO; +/** + * comedi_timeout() - busy-wait for a driver condition to occur. + * @dev: comedi_device struct + * @s: comedi_subdevice struct + * @insn: comedi_insn struct + * @cb: callback to check for the condition + * @context: private context from the driver + */ +int comedi_timeout(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + int (*cb)(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context), + unsigned long context) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(COMEDI_TIMEOUT_MS); + int ret; -attached: - /* do a little post-config cleanup */ - ret = postconfig(dev); - module_put(dev->driver->module); - if (ret < 0) { - __comedi_device_detach(dev); - return ret; + while (time_before(jiffies, timeout)) { + ret = cb(dev, s, insn, context); + if (ret != -EBUSY) + return ret; /* success (0) or non EBUSY errno */ + cpu_relax(); } - - if (!dev->board_name) { - printk(KERN_WARNING "BUG: dev->board_name=<%p>\n", - dev->board_name); - dev->board_name = "BUG"; + return -ETIMEDOUT; +} +EXPORT_SYMBOL_GPL(comedi_timeout); + +/** + * comedi_dio_insn_config() - boilerplate (*insn_config) for DIO subdevices. + * @dev: comedi_device struct + * @s: comedi_subdevice struct + * @insn: comedi_insn struct + * @data: parameters for the @insn + * @mask: io_bits mask for grouped channels + */ +int comedi_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data, + unsigned int mask) +{ + unsigned int chan_mask = 1 << CR_CHAN(insn->chanspec); + + if (!mask) + mask = chan_mask; + + switch (data[0]) { + case INSN_CONFIG_DIO_INPUT: + s->io_bits &= ~mask; + break; + + case INSN_CONFIG_DIO_OUTPUT: + s->io_bits |= mask; + break; + + case INSN_CONFIG_DIO_QUERY: + data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; + return insn->n; + + default: + return -EINVAL; } - smp_wmb(); - dev->attached = 1; return 0; } +EXPORT_SYMBOL_GPL(comedi_dio_insn_config); -int comedi_driver_register(struct comedi_driver *driver) +/** + * comedi_dio_update_state() - update the internal state of DIO subdevices. + * @s: comedi_subdevice struct + * @data: the channel mask and bits to update + */ +unsigned int comedi_dio_update_state(struct comedi_subdevice *s, + unsigned int *data) { - driver->next = comedi_drivers; - comedi_drivers = driver; + unsigned int chanmask = (s->n_chan < 32) ? ((1 << s->n_chan) - 1) + : 0xffffffff; + unsigned int mask = data[0] & chanmask; + unsigned int bits = data[1]; - return 0; + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + } + + return mask; } -EXPORT_SYMBOL(comedi_driver_register); +EXPORT_SYMBOL_GPL(comedi_dio_update_state); -int comedi_driver_unregister(struct comedi_driver *driver) +static int insn_rw_emulate_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - struct comedi_driver *prev; - int i; + struct comedi_insn new_insn; + int ret; + static const unsigned channels_per_bitfield = 32; - /* check for devices using this driver */ - for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(i); - struct comedi_device *dev; + unsigned chan = CR_CHAN(insn->chanspec); + const unsigned base_bitfield_channel = + (chan < channels_per_bitfield) ? 0 : chan; + unsigned int new_data[2]; - if (dev_file_info == NULL) - continue; - dev = dev_file_info->device; + memset(new_data, 0, sizeof(new_data)); + memset(&new_insn, 0, sizeof(new_insn)); + new_insn.insn = INSN_BITS; + new_insn.chanspec = base_bitfield_channel; + new_insn.n = 2; + new_insn.subdev = insn->subdev; - mutex_lock(&dev->mutex); - if (dev->attached && dev->driver == driver) { - if (dev->use_count) - printk(KERN_WARNING "BUG! detaching device with use_count=%d\n", - dev->use_count); - comedi_device_detach(dev); - } - mutex_unlock(&dev->mutex); + if (insn->insn == INSN_WRITE) { + if (!(s->subdev_flags & SDF_WRITABLE)) + return -EINVAL; + new_data[0] = 1 << (chan - base_bitfield_channel); /* mask */ + new_data[1] = data[0] ? (1 << (chan - base_bitfield_channel)) + : 0; /* bits */ } - if (comedi_drivers == driver) { - comedi_drivers = driver->next; - return 0; + ret = s->insn_bits(dev, s, &new_insn, new_data); + if (ret < 0) + return ret; + + if (insn->insn == INSN_READ) + data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1; + + return 1; +} + +static int __comedi_device_postconfig_async(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_async *async; + unsigned int buf_size; + int ret; + + if ((s->subdev_flags & (SDF_CMD_READ | SDF_CMD_WRITE)) == 0) { + dev_warn(dev->class_dev, + "async subdevices must support SDF_CMD_READ or SDF_CMD_WRITE\n"); + return -EINVAL; + } + if (!s->do_cmdtest) { + dev_warn(dev->class_dev, + "async subdevices must have a do_cmdtest() function\n"); + return -EINVAL; } - for (prev = comedi_drivers; prev->next; prev = prev->next) { - if (prev->next == driver) { - prev->next = driver->next; - return 0; - } + async = kzalloc(sizeof(*async), GFP_KERNEL); + if (!async) + return -ENOMEM; + + init_waitqueue_head(&async->wait_head); + s->async = async; + + async->max_bufsize = comedi_default_buf_maxsize_kb * 1024; + buf_size = comedi_default_buf_size_kb * 1024; + if (buf_size > async->max_bufsize) + buf_size = async->max_bufsize; + + if (comedi_buf_alloc(dev, s, buf_size) < 0) { + dev_warn(dev->class_dev, "Buffer allocation failed\n"); + return -ENOMEM; } - return -EINVAL; + if (s->buf_change) { + ret = s->buf_change(dev, s, buf_size); + if (ret < 0) + return ret; + } + + comedi_alloc_subdevice_minor(s); + + return 0; } -EXPORT_SYMBOL(comedi_driver_unregister); -static int postconfig(struct comedi_device *dev) +static int __comedi_device_postconfig(struct comedi_device *dev) { - int i; struct comedi_subdevice *s; - struct comedi_async *async = NULL; int ret; + int i; for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; if (s->type == COMEDI_SUBD_UNUSED) continue; + if (s->type == COMEDI_SUBD_DO) { + if (s->n_chan < 32) + s->io_bits = (1 << s->n_chan) - 1; + else + s->io_bits = 0xffffffff; + } + if (s->len_chanlist == 0) s->len_chanlist = 1; if (s->do_cmd) { - BUG_ON((s->subdev_flags & (SDF_CMD_READ | - SDF_CMD_WRITE)) == 0); - BUG_ON(!s->do_cmdtest); - - async = - kzalloc(sizeof(struct comedi_async), GFP_KERNEL); - if (async == NULL) { - printk(KERN_INFO - "failed to allocate async struct\n"); - return -ENOMEM; - } - init_waitqueue_head(&async->wait_head); - async->subdevice = s; - s->async = async; - -#define DEFAULT_BUF_MAXSIZE (64*1024) -#define DEFAULT_BUF_SIZE (64*1024) - - async->max_bufsize = DEFAULT_BUF_MAXSIZE; - - async->prealloc_buf = NULL; - async->prealloc_bufsz = 0; - if (comedi_buf_alloc(dev, s, DEFAULT_BUF_SIZE) < 0) { - printk(KERN_INFO "Buffer allocation failed\n"); - return -ENOMEM; - } - if (s->buf_change) { - ret = s->buf_change(dev, s, DEFAULT_BUF_SIZE); - if (ret < 0) - return ret; - } - comedi_alloc_subdevice_minor(dev, s); + ret = __comedi_device_postconfig_async(dev, s); + if (ret) + return ret; } if (!s->range_table && !s->range_table_list) @@ -301,18 +381,55 @@ static int postconfig(struct comedi_device *dev) return 0; } -/* generic recognize function for drivers - * that register their supported board names */ +/* do a little post-config cleanup */ +static int comedi_device_postconfig(struct comedi_device *dev) +{ + int ret; + + ret = __comedi_device_postconfig(dev); + if (ret < 0) + return ret; + down_write(&dev->attach_lock); + dev->attached = true; + up_write(&dev->attach_lock); + return 0; +} + +/* + * Generic recognize function for drivers that register their supported + * board names. + * + * 'driv->board_name' points to a 'const char *' member within the + * zeroth element of an array of some private board information + * structure, say 'struct foo_board' containing a member 'const char + * *board_name' that is initialized to point to a board name string that + * is one of the candidates matched against this function's 'name' + * parameter. + * + * 'driv->offset' is the size of the private board information + * structure, say 'sizeof(struct foo_board)', and 'driv->num_names' is + * the length of the array of private board information structures. + * + * If one of the board names in the array of private board information + * structures matches the name supplied to this function, the function + * returns a pointer to the pointer to the board name, otherwise it + * returns NULL. The return value ends up in the 'board_ptr' member of + * a 'struct comedi_device' that the low-level comedi driver's + * 'attach()' hook can convert to a point to a particular element of its + * array of private board information structures by subtracting the + * offset of the member that points to the board name. (No subtraction + * is required if the board name pointer is the first member of the + * private board information structure, which is generally the case.) + */ static void *comedi_recognize(struct comedi_driver *driv, const char *name) { - unsigned i; - const char *const *name_ptr = driv->board_name; + char **name_ptr = (char **)driv->board_name; + int i; + for (i = 0; i < driv->num_names; i++) { if (strcmp(*name_ptr, name) == 0) - return (void *)name_ptr; - name_ptr = - (const char *const *)((const char *)name_ptr + - driv->offset); + return name_ptr; + name_ptr = (void *)name_ptr + driv->offset; } return NULL; @@ -323,584 +440,287 @@ static void comedi_report_boards(struct comedi_driver *driv) unsigned int i; const char *const *name_ptr; - printk(KERN_INFO "comedi: valid board names for %s driver are:\n", - driv->driver_name); + pr_info("comedi: valid board names for %s driver are:\n", + driv->driver_name); name_ptr = driv->board_name; for (i = 0; i < driv->num_names; i++) { - printk(KERN_INFO " %s\n", *name_ptr); + pr_info(" %s\n", *name_ptr); name_ptr = (const char **)((char *)name_ptr + driv->offset); } if (driv->num_names == 0) - printk(KERN_INFO " %s\n", driv->driver_name); -} - -static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s) -{ - return -EINVAL; -} - -int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return -EINVAL; -} - -static int insn_rw_emulate_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct comedi_insn new_insn; + pr_info(" %s\n", driv->driver_name); +} + +/** + * comedi_load_firmware() - Request and load firmware for a device. + * @dev: comedi_device struct + * @hw_device: device struct for the comedi_device + * @name: the name of the firmware image + * @cb: callback to the upload the firmware image + * @context: private context from the driver + */ +int comedi_load_firmware(struct comedi_device *dev, + struct device *device, + const char *name, + int (*cb)(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context), + unsigned long context) +{ + const struct firmware *fw; int ret; - static const unsigned channels_per_bitfield = 32; - unsigned chan = CR_CHAN(insn->chanspec); - const unsigned base_bitfield_channel = - (chan < channels_per_bitfield) ? 0 : chan; - unsigned int new_data[2]; - memset(new_data, 0, sizeof(new_data)); - memset(&new_insn, 0, sizeof(new_insn)); - new_insn.insn = INSN_BITS; - new_insn.chanspec = base_bitfield_channel; - new_insn.n = 2; - new_insn.data = new_data; - new_insn.subdev = insn->subdev; + if (!cb) + return -EINVAL; - if (insn->insn == INSN_WRITE) { - if (!(s->subdev_flags & SDF_WRITABLE)) - return -EINVAL; - new_data[0] = 1 << (chan - base_bitfield_channel); /* mask */ - new_data[1] = data[0] ? (1 << (chan - base_bitfield_channel)) - : 0; /* bits */ + ret = request_firmware(&fw, name, device); + if (ret == 0) { + ret = cb(dev, fw->data, fw->size, context); + release_firmware(fw); } - ret = s->insn_bits(dev, s, &new_insn, new_data); - if (ret < 0) - return ret; - - if (insn->insn == INSN_READ) - data[0] = (new_data[1] >> (chan - base_bitfield_channel)) & 1; - - return 1; + return ret < 0 ? ret : 0; } +EXPORT_SYMBOL_GPL(comedi_load_firmware); -static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr) +/** + * __comedi_request_region() - Request an I/O reqion for a legacy driver. + * @dev: comedi_device struct + * @start: base address of the I/O reqion + * @len: length of the I/O region + */ +int __comedi_request_region(struct comedi_device *dev, + unsigned long start, unsigned long len) { - unsigned long ret = 0UL; - pmd_t *pmd; - pte_t *ptep, pte; - pud_t *pud; - - if (!pgd_none(*pgd)) { - pud = pud_offset(pgd, adr); - pmd = pmd_offset(pud, adr); - if (!pmd_none(*pmd)) { - ptep = pte_offset_kernel(pmd, adr); - pte = *ptep; - if (pte_present(pte)) { - ret = (unsigned long) - page_address(pte_page(pte)); - ret |= (adr & (PAGE_SIZE - 1)); - } - } + if (!start) { + dev_warn(dev->class_dev, + "%s: a I/O base address must be specified\n", + dev->board_name); + return -EINVAL; } - return ret; -} -static inline unsigned long kvirt_to_kva(unsigned long adr) -{ - unsigned long va, kva; - - va = adr; - kva = uvirt_to_kva(pgd_offset_k(va), va); + if (!request_region(start, len, dev->board_name)) { + dev_warn(dev->class_dev, "%s: I/O port conflict (%#lx,%lu)\n", + dev->board_name, start, len); + return -EIO; + } - return kva; + return 0; } +EXPORT_SYMBOL_GPL(__comedi_request_region); -int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned long new_size) +/** + * comedi_request_region() - Request an I/O reqion for a legacy driver. + * @dev: comedi_device struct + * @start: base address of the I/O reqion + * @len: length of the I/O region + */ +int comedi_request_region(struct comedi_device *dev, + unsigned long start, unsigned long len) { - struct comedi_async *async = s->async; - - /* Round up new_size to multiple of PAGE_SIZE */ - new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK; - - /* if no change is required, do nothing */ - if (async->prealloc_buf && async->prealloc_bufsz == new_size) - return 0; + int ret; - /* deallocate old buffer */ - if (async->prealloc_buf) { - vunmap(async->prealloc_buf); - async->prealloc_buf = NULL; - async->prealloc_bufsz = 0; - } - if (async->buf_page_list) { - unsigned i; - for (i = 0; i < async->n_buf_pages; ++i) { - if (async->buf_page_list[i].virt_addr) { - clear_bit(PG_reserved, - &(virt_to_page(async->buf_page_list[i]. - virt_addr)->flags)); - if (s->async_dma_dir != DMA_NONE) { - dma_free_coherent(dev->hw_dev, - PAGE_SIZE, - async-> - buf_page_list - [i].virt_addr, - async-> - buf_page_list - [i].dma_addr); - } else { - free_page((unsigned long) - async->buf_page_list[i]. - virt_addr); - } - } - } - vfree(async->buf_page_list); - async->buf_page_list = NULL; - async->n_buf_pages = 0; + ret = __comedi_request_region(dev, start, len); + if (ret == 0) { + dev->iobase = start; + dev->iolen = len; } - /* allocate new buffer */ - if (new_size) { - unsigned i = 0; - unsigned n_pages = new_size >> PAGE_SHIFT; - struct page **pages = NULL; - - async->buf_page_list = - vzalloc(sizeof(struct comedi_buf_page) * n_pages); - if (async->buf_page_list) - pages = vmalloc(sizeof(struct page *) * n_pages); - - if (pages) { - for (i = 0; i < n_pages; i++) { - if (s->async_dma_dir != DMA_NONE) { - async->buf_page_list[i].virt_addr = - dma_alloc_coherent(dev->hw_dev, - PAGE_SIZE, - &async-> - buf_page_list - [i].dma_addr, - GFP_KERNEL | - __GFP_COMP); - } else { - async->buf_page_list[i].virt_addr = - (void *) - get_zeroed_page(GFP_KERNEL); - } - if (async->buf_page_list[i].virt_addr == NULL) - break; - - set_bit(PG_reserved, - &(virt_to_page(async->buf_page_list[i]. - virt_addr)->flags)); - pages[i] = virt_to_page(async->buf_page_list[i]. - virt_addr); - } - } - if (i == n_pages) { - async->prealloc_buf = - vmap(pages, n_pages, VM_MAP, PAGE_KERNEL_NOCACHE); - } - vfree(pages); - - if (async->prealloc_buf == NULL) { - /* Some allocation failed above. */ - if (async->buf_page_list) { - for (i = 0; i < n_pages; i++) { - if (async->buf_page_list[i].virt_addr == - NULL) { - break; - } - clear_bit(PG_reserved, - &(virt_to_page(async-> - buf_page_list[i]. - virt_addr)->flags)); - if (s->async_dma_dir != DMA_NONE) { - dma_free_coherent(dev->hw_dev, - PAGE_SIZE, - async-> - buf_page_list - [i].virt_addr, - async-> - buf_page_list - [i].dma_addr); - } else { - free_page((unsigned long) - async->buf_page_list - [i].virt_addr); - } - } - vfree(async->buf_page_list); - async->buf_page_list = NULL; - } - return -ENOMEM; - } - async->n_buf_pages = n_pages; - } - async->prealloc_bufsz = new_size; - return 0; + return ret; } +EXPORT_SYMBOL_GPL(comedi_request_region); -/* munging is applied to data by core as it passes between user - * and kernel space */ -static unsigned int comedi_buf_munge(struct comedi_async *async, - unsigned int num_bytes) +/** + * comedi_legacy_detach() - A generic (*detach) function for legacy drivers. + * @dev: comedi_device struct + */ +void comedi_legacy_detach(struct comedi_device *dev) { - struct comedi_subdevice *s = async->subdevice; - unsigned int count = 0; - const unsigned num_sample_bytes = bytes_per_sample(s); - - if (s->munge == NULL || (async->cmd.flags & CMDF_RAWDATA)) { - async->munge_count += num_bytes; - BUG_ON((int)(async->munge_count - async->buf_write_count) > 0); - return num_bytes; + if (dev->irq) { + free_irq(dev->irq, dev); + dev->irq = 0; } - /* don't munge partial samples */ - num_bytes -= num_bytes % num_sample_bytes; - while (count < num_bytes) { - int block_size; - - block_size = num_bytes - count; - if (block_size < 0) { - printk(KERN_WARNING - "%s: %s: bug! block_size is negative\n", - __FILE__, __func__); - break; - } - if ((int)(async->munge_ptr + block_size - - async->prealloc_bufsz) > 0) - block_size = async->prealloc_bufsz - async->munge_ptr; - - s->munge(s->device, s, async->prealloc_buf + async->munge_ptr, - block_size, async->munge_chan); - - smp_wmb(); /* barrier insures data is munged in buffer - * before munge_count is incremented */ - - async->munge_chan += block_size / num_sample_bytes; - async->munge_chan %= async->cmd.chanlist_len; - async->munge_count += block_size; - async->munge_ptr += block_size; - async->munge_ptr %= async->prealloc_bufsz; - count += block_size; + if (dev->iobase && dev->iolen) { + release_region(dev->iobase, dev->iolen); + dev->iobase = 0; + dev->iolen = 0; } - BUG_ON((int)(async->munge_count - async->buf_write_count) > 0); - return count; -} - -unsigned int comedi_buf_write_n_available(struct comedi_async *async) -{ - unsigned int free_end; - unsigned int nbytes; - - if (async == NULL) - return 0; - - free_end = async->buf_read_count + async->prealloc_bufsz; - nbytes = free_end - async->buf_write_alloc_count; - nbytes -= nbytes % bytes_per_sample(async->subdevice); - /* barrier insures the read of buf_read_count in this - query occurs before any following writes to the buffer which - might be based on the return value from this query. - */ - smp_mb(); - return nbytes; -} - -/* allocates chunk for the writer from free buffer space */ -unsigned int comedi_buf_write_alloc(struct comedi_async *async, - unsigned int nbytes) -{ - unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; - - if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0) - nbytes = free_end - async->buf_write_alloc_count; - - async->buf_write_alloc_count += nbytes; - /* barrier insures the read of buf_read_count above occurs before - we write data to the write-alloc'ed buffer space */ - smp_mb(); - return nbytes; } -EXPORT_SYMBOL(comedi_buf_write_alloc); +EXPORT_SYMBOL_GPL(comedi_legacy_detach); -/* allocates nothing unless it can completely fulfill the request */ -unsigned int comedi_buf_write_alloc_strict(struct comedi_async *async, - unsigned int nbytes) +int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - unsigned int free_end = async->buf_read_count + async->prealloc_bufsz; - - if ((int)(async->buf_write_alloc_count + nbytes - free_end) > 0) - nbytes = 0; + struct comedi_driver *driv; + int ret; - async->buf_write_alloc_count += nbytes; - /* barrier insures the read of buf_read_count above occurs before - we write data to the write-alloc'ed buffer space */ - smp_mb(); - return nbytes; -} + if (dev->attached) + return -EBUSY; -/* transfers a chunk from writer to filled buffer space */ -unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes) -{ - if ((int)(async->buf_write_count + nbytes - - async->buf_write_alloc_count) > 0) { - printk(KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n"); - nbytes = async->buf_write_alloc_count - async->buf_write_count; + mutex_lock(&comedi_drivers_list_lock); + for (driv = comedi_drivers; driv; driv = driv->next) { + if (!try_module_get(driv->module)) + continue; + if (driv->num_names) { + dev->board_ptr = comedi_recognize(driv, it->board_name); + if (dev->board_ptr) + break; + } else if (strcmp(driv->driver_name, it->board_name) == 0) + break; + module_put(driv->module); } - async->buf_write_count += nbytes; - async->buf_write_ptr += nbytes; - comedi_buf_munge(async, async->buf_write_count - async->munge_count); - if (async->buf_write_ptr >= async->prealloc_bufsz) - async->buf_write_ptr %= async->prealloc_bufsz; - - return nbytes; -} -EXPORT_SYMBOL(comedi_buf_write_free); - -/* allocates a chunk for the reader from filled (and munged) buffer space */ -unsigned comedi_buf_read_alloc(struct comedi_async *async, unsigned nbytes) -{ - if ((int)(async->buf_read_alloc_count + nbytes - async->munge_count) > - 0) { - nbytes = async->munge_count - async->buf_read_alloc_count; + if (driv == NULL) { + /* recognize has failed if we get here */ + /* report valid board names before returning error */ + for (driv = comedi_drivers; driv; driv = driv->next) { + if (!try_module_get(driv->module)) + continue; + comedi_report_boards(driv); + module_put(driv->module); + } + ret = -EIO; + goto out; } - async->buf_read_alloc_count += nbytes; - /* barrier insures read of munge_count occurs before we actually read - data out of buffer */ - smp_rmb(); - return nbytes; -} -EXPORT_SYMBOL(comedi_buf_read_alloc); - -/* transfers control of a chunk from reader to free buffer space */ -unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes) -{ - /* barrier insures data has been read out of - * buffer before read count is incremented */ - smp_mb(); - if ((int)(async->buf_read_count + nbytes - - async->buf_read_alloc_count) > 0) { - printk(KERN_INFO - "comedi: attempted to read-free more bytes than have been read-allocated.\n"); - nbytes = async->buf_read_alloc_count - async->buf_read_count; + if (driv->attach == NULL) { + /* driver does not support manual configuration */ + dev_warn(dev->class_dev, + "driver '%s' does not support attach using comedi_config\n", + driv->driver_name); + module_put(driv->module); + ret = -ENOSYS; + goto out; } - async->buf_read_count += nbytes; - async->buf_read_ptr += nbytes; - async->buf_read_ptr %= async->prealloc_bufsz; - return nbytes; -} -EXPORT_SYMBOL(comedi_buf_read_free); - -void comedi_buf_memcpy_to(struct comedi_async *async, unsigned int offset, - const void *data, unsigned int num_bytes) -{ - unsigned int write_ptr = async->buf_write_ptr + offset; - - if (write_ptr >= async->prealloc_bufsz) - write_ptr %= async->prealloc_bufsz; - - while (num_bytes) { - unsigned int block_size; - - if (write_ptr + num_bytes > async->prealloc_bufsz) - block_size = async->prealloc_bufsz - write_ptr; - else - block_size = num_bytes; - - memcpy(async->prealloc_buf + write_ptr, data, block_size); - - data += block_size; - num_bytes -= block_size; - - write_ptr = 0; + /* initialize dev->driver here so + * comedi_error() can be called from attach */ + dev->driver = driv; + dev->board_name = dev->board_ptr ? *(const char **)dev->board_ptr + : dev->driver->driver_name; + ret = driv->attach(dev, it); + if (ret >= 0) + ret = comedi_device_postconfig(dev); + if (ret < 0) { + comedi_device_detach(dev); + module_put(driv->module); } + /* On success, the driver module count has been incremented. */ +out: + mutex_unlock(&comedi_drivers_list_lock); + return ret; } -EXPORT_SYMBOL(comedi_buf_memcpy_to); -void comedi_buf_memcpy_from(struct comedi_async *async, unsigned int offset, - void *dest, unsigned int nbytes) +int comedi_auto_config(struct device *hardware_device, + struct comedi_driver *driver, unsigned long context) { - void *src; - unsigned int read_ptr = async->buf_read_ptr + offset; - - if (read_ptr >= async->prealloc_bufsz) - read_ptr %= async->prealloc_bufsz; - - while (nbytes) { - unsigned int block_size; - - src = async->prealloc_buf + read_ptr; - - if (nbytes >= async->prealloc_bufsz - read_ptr) - block_size = async->prealloc_bufsz - read_ptr; - else - block_size = nbytes; + struct comedi_device *dev; + int ret; - memcpy(dest, src, block_size); - nbytes -= block_size; - dest += block_size; - read_ptr = 0; + if (!hardware_device) { + pr_warn("BUG! comedi_auto_config called with NULL hardware_device\n"); + return -EINVAL; } -} -EXPORT_SYMBOL(comedi_buf_memcpy_from); - -unsigned int comedi_buf_read_n_available(struct comedi_async *async) -{ - unsigned num_bytes; - - if (async == NULL) - return 0; - num_bytes = async->munge_count - async->buf_read_count; - /* barrier insures the read of munge_count in this - query occurs before any following reads of the buffer which - might be based on the return value from this query. - */ - smp_rmb(); - return num_bytes; -} -EXPORT_SYMBOL(comedi_buf_read_n_available); - -int comedi_buf_get(struct comedi_async *async, short *x) -{ - unsigned int n = comedi_buf_read_n_available(async); - - if (n < sizeof(short)) - return 0; - comedi_buf_read_alloc(async, sizeof(short)); - *x = *(short *)(async->prealloc_buf + async->buf_read_ptr); - comedi_buf_read_free(async, sizeof(short)); - return 1; -} -EXPORT_SYMBOL(comedi_buf_get); - -int comedi_buf_put(struct comedi_async *async, short x) -{ - unsigned int n = comedi_buf_write_alloc_strict(async, sizeof(short)); - - if (n < sizeof(short)) { - async->events |= COMEDI_CB_ERROR; - return 0; + if (!driver) { + dev_warn(hardware_device, + "BUG! comedi_auto_config called with NULL comedi driver\n"); + return -EINVAL; } - *(short *)(async->prealloc_buf + async->buf_write_ptr) = x; - comedi_buf_write_free(async, sizeof(short)); - return 1; -} -EXPORT_SYMBOL(comedi_buf_put); - -void comedi_reset_async_buf(struct comedi_async *async) -{ - async->buf_write_alloc_count = 0; - async->buf_write_count = 0; - async->buf_read_alloc_count = 0; - async->buf_read_count = 0; - async->buf_write_ptr = 0; - async->buf_read_ptr = 0; - - async->cur_chan = 0; - async->scan_progress = 0; - async->munge_chan = 0; - async->munge_count = 0; - async->munge_ptr = 0; - - async->events = 0; -} - -static int comedi_auto_config(struct device *hardware_device, - const char *board_name, const int *options, - unsigned num_options) -{ - struct comedi_devconfig it; - int minor; - struct comedi_device_file_info *dev_file_info; - int retval; - unsigned *private_data = NULL; - - if (!comedi_autoconfig) { - dev_set_drvdata(hardware_device, NULL); - return 0; + if (!driver->auto_attach) { + dev_warn(hardware_device, + "BUG! comedi driver '%s' has no auto_attach handler\n", + driver->driver_name); + return -EINVAL; } - minor = comedi_alloc_board_minor(hardware_device); - if (minor < 0) - return minor; - - private_data = kmalloc(sizeof(unsigned), GFP_KERNEL); - if (private_data == NULL) { - retval = -ENOMEM; - goto cleanup; + dev = comedi_alloc_board_minor(hardware_device); + if (IS_ERR(dev)) { + dev_warn(hardware_device, + "driver '%s' could not create device.\n", + driver->driver_name); + return PTR_ERR(dev); } - *private_data = minor; - dev_set_drvdata(hardware_device, private_data); - - dev_file_info = comedi_get_device_file_info(minor); - - memset(&it, 0, sizeof(it)); - strncpy(it.board_name, board_name, COMEDI_NAMELEN); - it.board_name[COMEDI_NAMELEN - 1] = '\0'; - BUG_ON(num_options > COMEDI_NDEVCONFOPTS); - memcpy(it.options, options, num_options * sizeof(int)); + /* Note: comedi_alloc_board_minor() locked dev->mutex. */ - mutex_lock(&dev_file_info->device->mutex); - retval = comedi_device_attach(dev_file_info->device, &it); - mutex_unlock(&dev_file_info->device->mutex); + dev->driver = driver; + dev->board_name = dev->driver->driver_name; + ret = driver->auto_attach(dev, context); + if (ret >= 0) + ret = comedi_device_postconfig(dev); + mutex_unlock(&dev->mutex); -cleanup: - if (retval < 0) { - kfree(private_data); - comedi_free_board_minor(minor); + if (ret < 0) { + dev_warn(hardware_device, + "driver '%s' failed to auto-configure device.\n", + driver->driver_name); + comedi_release_hardware_device(hardware_device); + } else { + /* + * class_dev should be set properly here + * after a successful auto config + */ + dev_info(dev->class_dev, + "driver '%s' has successfully auto-configured '%s'.\n", + driver->driver_name, dev->board_name); } - return retval; + return ret; } +EXPORT_SYMBOL_GPL(comedi_auto_config); -static void comedi_auto_unconfig(struct device *hardware_device) +void comedi_auto_unconfig(struct device *hardware_device) { - unsigned *minor = (unsigned *)dev_get_drvdata(hardware_device); - if (minor == NULL) + if (hardware_device == NULL) return; - - BUG_ON(*minor >= COMEDI_NUM_BOARD_MINORS); - - comedi_free_board_minor(*minor); - dev_set_drvdata(hardware_device, NULL); - kfree(minor); + comedi_release_hardware_device(hardware_device); } +EXPORT_SYMBOL_GPL(comedi_auto_unconfig); -int comedi_pci_auto_config(struct pci_dev *pcidev, const char *board_name) +int comedi_driver_register(struct comedi_driver *driver) { - int options[2]; - - /* pci bus */ - options[0] = pcidev->bus->number; - /* pci slot */ - options[1] = PCI_SLOT(pcidev->devfn); + mutex_lock(&comedi_drivers_list_lock); + driver->next = comedi_drivers; + comedi_drivers = driver; + mutex_unlock(&comedi_drivers_list_lock); - return comedi_auto_config(&pcidev->dev, board_name, - options, ARRAY_SIZE(options)); + return 0; } -EXPORT_SYMBOL_GPL(comedi_pci_auto_config); +EXPORT_SYMBOL_GPL(comedi_driver_register); -void comedi_pci_auto_unconfig(struct pci_dev *pcidev) +void comedi_driver_unregister(struct comedi_driver *driver) { - comedi_auto_unconfig(&pcidev->dev); -} -EXPORT_SYMBOL_GPL(comedi_pci_auto_unconfig); + struct comedi_driver *prev; + int i; -int comedi_usb_auto_config(struct usb_device *usbdev, const char *board_name) -{ - BUG_ON(usbdev == NULL); - return comedi_auto_config(&usbdev->dev, board_name, NULL, 0); -} -EXPORT_SYMBOL_GPL(comedi_usb_auto_config); + /* unlink the driver */ + mutex_lock(&comedi_drivers_list_lock); + if (comedi_drivers == driver) { + comedi_drivers = driver->next; + } else { + for (prev = comedi_drivers; prev->next; prev = prev->next) { + if (prev->next == driver) { + prev->next = driver->next; + break; + } + } + } + mutex_unlock(&comedi_drivers_list_lock); -void comedi_usb_auto_unconfig(struct usb_device *usbdev) -{ - BUG_ON(usbdev == NULL); - comedi_auto_unconfig(&usbdev->dev); + /* check for devices using this driver */ + for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { + struct comedi_device *dev = comedi_dev_get_from_minor(i); + + if (!dev) + continue; + + mutex_lock(&dev->mutex); + if (dev->attached && dev->driver == driver) { + if (dev->use_count) + dev_warn(dev->class_dev, + "BUG! detaching device with use_count=%d\n", + dev->use_count); + comedi_device_detach(dev); + } + mutex_unlock(&dev->mutex); + comedi_dev_put(dev); + } } -EXPORT_SYMBOL_GPL(comedi_usb_auto_unconfig); +EXPORT_SYMBOL_GPL(comedi_driver_unregister); diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index 3eb45d46e05..5829b46b757 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _8253_H @@ -26,106 +21,20 @@ #include "../comedi.h" -#define i8253_cascade_ns_to_timer i8253_cascade_ns_to_timer_2div - -static inline void i8253_cascade_ns_to_timer_2div_old(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) -{ - int divider; - int div1, div2; - int div1_glb, div2_glb, ns_glb; - int div1_lub, div2_lub, ns_lub; - int ns; - - divider = (*nanosec + i8253_osc_base / 2) / i8253_osc_base; - - /* find 2 integers 1<={x,y}<=65536 such that x*y is - close to divider */ - - div1_lub = div2_lub = 0; - div1_glb = div2_glb = 0; - - ns_glb = 0; - ns_lub = 0xffffffff; - - div2 = 0x10000; - for (div1 = divider / 65536 + 1; div1 < div2; div1++) { - div2 = divider / div1; - - ns = i8253_osc_base * div1 * div2; - if (ns <= *nanosec && ns > ns_glb) { - ns_glb = ns; - div1_glb = div1; - div2_glb = div2; - } - - div2++; - if (div2 <= 65536) { - ns = i8253_osc_base * div1 * div2; - if (ns > *nanosec && ns < ns_lub) { - ns_lub = ns; - div1_lub = div1; - div2_lub = div2; - } - } - } - - *nanosec = div1_lub * div2_lub * i8253_osc_base; - *d1 = div1_lub & 0xffff; - *d2 = div2_lub & 0xffff; - return; -} - -static inline void i8253_cascade_ns_to_timer_power(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) -{ - int div1, div2; - int base; - - for (div1 = 2; div1 <= (1 << 16); div1 <<= 1) { - base = i8253_osc_base * div1; - round_mode &= TRIG_ROUND_MASK; - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - div2 = (*nanosec + base / 2) / base; - break; - case TRIG_ROUND_DOWN: - div2 = (*nanosec) / base; - break; - case TRIG_ROUND_UP: - div2 = (*nanosec + base - 1) / base; - break; - } - if (div2 < 2) - div2 = 2; - if (div2 <= 65536) { - *nanosec = div2 * base; - *d1 = div1 & 0xffff; - *d2 = div2 & 0xffff; - return; - } - } - - /* shouldn't get here */ - div1 = 0x10000; - div2 = 0x10000; - *nanosec = div1 * div2 * i8253_osc_base; - *d1 = div1 & 0xffff; - *d2 = div2 & 0xffff; -} - -static inline void i8253_cascade_ns_to_timer_2div(int i8253_osc_base, - unsigned int *d1, - unsigned int *d2, - unsigned int *nanosec, - int round_mode) +/* + * Common oscillator base values in nanoseconds + */ +#define I8254_OSC_BASE_10MHZ 100 +#define I8254_OSC_BASE_5MHZ 200 +#define I8254_OSC_BASE_4MHZ 250 +#define I8254_OSC_BASE_2MHZ 500 +#define I8254_OSC_BASE_1MHZ 1000 + +static inline void i8253_cascade_ns_to_timer(int i8253_osc_base, + unsigned int *d1, + unsigned int *d2, + unsigned int *nanosec, + int round_mode) { unsigned int divider; unsigned int div1, div2; @@ -262,8 +171,10 @@ static inline int i8254_load(unsigned long base_address, unsigned int regshift, return 0; } -static inline int i8254_mm_load(void *base_address, unsigned int regshift, - unsigned int counter_number, unsigned int count, +static inline int i8254_mm_load(void __iomem *base_address, + unsigned int regshift, + unsigned int counter_number, + unsigned int count, unsigned int mode) { unsigned int byte; @@ -311,7 +222,8 @@ static inline int i8254_read(unsigned long base_address, unsigned int regshift, return ret; } -static inline int i8254_mm_read(void *base_address, unsigned int regshift, +static inline int i8254_mm_read(void __iomem *base_address, + unsigned int regshift, unsigned int counter_number) { unsigned int byte; @@ -348,7 +260,7 @@ static inline void i8254_write(unsigned long base_address, outb(byte, base_address + (counter_number << regshift)); } -static inline void i8254_mm_write(void *base_address, +static inline void i8254_mm_write(void __iomem *base_address, unsigned int regshift, unsigned int counter_number, unsigned int count) @@ -379,7 +291,7 @@ static inline int i8254_set_mode(unsigned long base_address, if (counter_number > 2) return -1; - if (mode > (I8254_MODE5 | I8254_BINARY)) + if (mode > (I8254_MODE5 | I8254_BCD)) return -1; byte = counter_number << 6; @@ -390,7 +302,7 @@ static inline int i8254_set_mode(unsigned long base_address, return 0; } -static inline int i8254_mm_set_mode(void *base_address, +static inline int i8254_mm_set_mode(void __iomem *base_address, unsigned int regshift, unsigned int counter_number, unsigned int mode) @@ -399,7 +311,7 @@ static inline int i8254_mm_set_mode(void *base_address, if (counter_number > 2) return -1; - if (mode > (I8254_MODE5 | I8254_BINARY)) + if (mode > (I8254_MODE5 | I8254_BCD)) return -1; byte = counter_number << 6; @@ -419,7 +331,7 @@ static inline int i8254_status(unsigned long base_address, return inb(base_address + (counter_number << regshift)); } -static inline int i8254_mm_status(void *base_address, +static inline int i8254_mm_status(void __iomem *base_address, unsigned int regshift, unsigned int counter_number) { diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index 6c26ac887ee..46113a37413 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: 8255 @@ -60,15 +55,15 @@ I/O port base address can be found in the output of 'lspci -v'. set up the subdevice in the attach function of the driver by calling: - subdev_8255_init(device, subdevice, callback_function, arg) + subdev_8255_init(device, subdevice, io_function, iobase) device and subdevice are pointers to the device and subdevice - structures. callback_function will be called to provide the + structures. io_function will be called to provide the low-level input/output to the device, i.e., actual register - access. callback_function will be called with the value of arg + access. io_function will be called with the value of iobase as the last parameter. If the 8255 device is mapped as 4 - consecutive I/O ports, you can use NULL for callback_function - and the I/O port base for arg, and an internal function will + consecutive I/O ports, you can use NULL for io_function + and the I/O port base for iobase, and an internal function will handle the register access. In addition, if the main driver handles interrupts, you can @@ -78,16 +73,16 @@ I/O port base address can be found in the output of 'lspci -v'. will copy the latched value to a Comedi buffer. */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/slab.h> +#include "comedi_fc.h" #include "8255.h" -#define _8255_SIZE 4 +#define _8255_SIZE 4 -#define _8255_DATA 0 -#define _8255_CR 3 +#define _8255_DATA 0 +#define _8255_CR 3 #define CR_C_LO_IO 0x01 #define CR_B_IO 0x02 @@ -97,133 +92,74 @@ I/O port base address can be found in the output of 'lspci -v'. #define CR_A_MODE(a) ((a)<<5) #define CR_CW 0x80 -struct subdev_8255_struct { - unsigned long cb_arg; - int (*cb_func) (int, int, int, unsigned long); - int have_irq; -}; - -#define CALLBACK_ARG (((struct subdev_8255_struct *)s->private)->cb_arg) -#define CALLBACK_FUNC (((struct subdev_8255_struct *)s->private)->cb_func) -#define subdevpriv ((struct subdev_8255_struct *)s->private) - -static int dev_8255_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dev_8255_detach(struct comedi_device *dev); -static struct comedi_driver driver_8255 = { - .driver_name = "8255", - .module = THIS_MODULE, - .attach = dev_8255_attach, - .detach = dev_8255_detach, +struct subdev_8255_private { + unsigned long iobase; + int (*io)(int, int, int, unsigned long); }; -static int __init driver_8255_init_module(void) +static int subdev_8255_io(int dir, int port, int data, unsigned long iobase) { - return comedi_driver_register(&driver_8255); -} - -static void __exit driver_8255_cleanup_module(void) -{ - comedi_driver_unregister(&driver_8255); + if (dir) { + outb(data, iobase + port); + return 0; + } else { + return inb(iobase + port); + } } -module_init(driver_8255_init_module); -module_exit(driver_8255_cleanup_module); - -static void do_config(struct comedi_device *dev, struct comedi_subdevice *s); - void subdev_8255_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) { - short d; + struct subdev_8255_private *spriv = s->private; + unsigned long iobase = spriv->iobase; + unsigned short d; - d = CALLBACK_FUNC(0, _8255_DATA, 0, CALLBACK_ARG); - d |= (CALLBACK_FUNC(0, _8255_DATA + 1, 0, CALLBACK_ARG) << 8); + d = spriv->io(0, _8255_DATA, 0, iobase); + d |= (spriv->io(0, _8255_DATA + 1, 0, iobase) << 8); - comedi_buf_put(s->async, d); + comedi_buf_put(s, d); s->async->events |= COMEDI_CB_EOS; comedi_event(dev, s); } -EXPORT_SYMBOL(subdev_8255_interrupt); - -static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) -{ - unsigned long iobase = arg; - - if (dir) { - outb(data, iobase + port); - return 0; - } else { - return inb(iobase + port); - } -} +EXPORT_SYMBOL_GPL(subdev_8255_interrupt); static int subdev_8255_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - if (data[0] & 0xff) - CALLBACK_FUNC(1, _8255_DATA, s->state & 0xff, - CALLBACK_ARG); - if (data[0] & 0xff00) - CALLBACK_FUNC(1, _8255_DATA + 1, (s->state >> 8) & 0xff, - CALLBACK_ARG); - if (data[0] & 0xff0000) - CALLBACK_FUNC(1, _8255_DATA + 2, - (s->state >> 16) & 0xff, CALLBACK_ARG); - } - - data[1] = CALLBACK_FUNC(0, _8255_DATA, 0, CALLBACK_ARG); - data[1] |= (CALLBACK_FUNC(0, _8255_DATA + 1, 0, CALLBACK_ARG) << 8); - data[1] |= (CALLBACK_FUNC(0, _8255_DATA + 2, 0, CALLBACK_ARG) << 16); - - return 2; -} - -static int subdev_8255_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct subdev_8255_private *spriv = s->private; + unsigned long iobase = spriv->iobase; unsigned int mask; - unsigned int bits; - - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x0000ff) - bits = 0x0000ff; - else if (mask & 0x00ff00) - bits = 0x00ff00; - else if (mask & 0x0f0000) - bits = 0x0f0000; - else - bits = 0xf00000; - - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; + unsigned int v; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0xff) + spriv->io(1, _8255_DATA, s->state & 0xff, iobase); + if (mask & 0xff00) + spriv->io(1, _8255_DATA + 1, (s->state >> 8) & 0xff, + iobase); + if (mask & 0xff0000) + spriv->io(1, _8255_DATA + 2, (s->state >> 16) & 0xff, + iobase); } - do_config(dev, s); + 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); + + data[1] = v; - return 1; + return insn->n; } -static void do_config(struct comedi_device *dev, struct comedi_subdevice *s) +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; int config; config = CR_CW; @@ -236,73 +172,67 @@ static void do_config(struct comedi_device *dev, struct comedi_subdevice *s) config |= CR_C_LO_IO; if (!(s->io_bits & 0xf00000)) config |= CR_C_HI_IO; - CALLBACK_FUNC(1, _8255_CR, config, CALLBACK_ARG); + + spriv->io(1, _8255_CR, config, iobase); } -static int subdev_8255_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int subdev_8255_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int err = 0; - unsigned int tmp; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; - /* step 1 */ + if (chan < 8) + mask = 0x0000ff; + else if (chan < 16) + mask = 0x00ff00; + else if (chan < 20) + mask = 0x0f0000; + else + mask = 0xf00000; - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + subdev_8255_do_config(dev, s); - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + return insn->n; +} - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; +static int subdev_8255_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + /* 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 2 */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3 */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->scan_end_arg != 1) { - cmd->scan_end_arg = 1; - err++; - } - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + 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; @@ -332,60 +262,50 @@ static int subdev_8255_cancel(struct comedi_device *dev, } int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*cb) (int, int, int, unsigned long), - unsigned long arg) + int (*io)(int, int, int, unsigned long), + unsigned long iobase) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 24; - s->range_table = &range_digital; - s->maxdata = 1; - - s->private = kmalloc(sizeof(struct subdev_8255_struct), GFP_KERNEL); - if (!s->private) + struct subdev_8255_private *spriv; + + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) return -ENOMEM; - CALLBACK_ARG = arg; - if (cb == NULL) - CALLBACK_FUNC = subdev_8255_cb; - else - CALLBACK_FUNC = cb; - s->insn_bits = subdev_8255_insn; - s->insn_config = subdev_8255_insn_config; + spriv->iobase = iobase; + spriv->io = io ? io : subdev_8255_io; + + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->range_table = &range_digital; + s->maxdata = 1; + s->insn_bits = subdev_8255_insn; + s->insn_config = subdev_8255_insn_config; - s->state = 0; - s->io_bits = 0; - do_config(dev, s); + subdev_8255_do_config(dev, s); return 0; } -EXPORT_SYMBOL(subdev_8255_init); +EXPORT_SYMBOL_GPL(subdev_8255_init); int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, - int (*cb) (int, int, int, unsigned long), - unsigned long arg) + int (*io)(int, int, int, unsigned long), + unsigned long iobase) { int ret; - ret = subdev_8255_init(dev, s, cb, arg); - if (ret < 0) + ret = subdev_8255_init(dev, s, io, iobase); + if (ret) return ret; - s->do_cmdtest = subdev_8255_cmdtest; - s->do_cmd = subdev_8255_cmd; - s->cancel = subdev_8255_cancel; - - subdevpriv->have_irq = 1; + s->len_chanlist = 1; + s->do_cmdtest = subdev_8255_cmdtest; + s->do_cmd = subdev_8255_cmd; + s->cancel = subdev_8255_cancel; return 0; } -EXPORT_SYMBOL(subdev_8255_init_irq); - -void subdev_8255_cleanup(struct comedi_device *dev, struct comedi_subdevice *s) -{ - kfree(s->private); -} -EXPORT_SYMBOL(subdev_8255_cleanup); +EXPORT_SYMBOL_GPL(subdev_8255_init_irq); /* @@ -396,72 +316,65 @@ EXPORT_SYMBOL(subdev_8255_cleanup); static int dev_8255_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + struct comedi_subdevice *s; int ret; unsigned long iobase; int i; - dev->board_name = "8255"; - for (i = 0; i < COMEDI_NDEVCONFOPTS; i++) { iobase = it->options[i]; if (!iobase) break; } if (i == 0) { - printk(KERN_WARNING - "comedi%d: 8255: no devices specified\n", dev->minor); + dev_warn(dev->class_dev, "no devices specified\n"); return -EINVAL; } - ret = alloc_subdevices(dev, i); - if (ret < 0) { - /* FIXME this printk call should give a proper message, the - * below line just maintains previous functionality */ - printk("comedi%d: 8255:", dev->minor); + ret = comedi_alloc_subdevices(dev, i); + if (ret) return ret; - } - - printk(KERN_INFO "comedi%d: 8255:", dev->minor); for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; iobase = it->options[i]; - printk(" 0x%04lx", iobase); - if (!request_region(iobase, _8255_SIZE, "8255")) { - printk(" (I/O port conflict)"); - - dev->subdevices[i].type = COMEDI_SUBD_UNUSED; + ret = __comedi_request_region(dev, iobase, _8255_SIZE); + if (ret) { + s->type = COMEDI_SUBD_UNUSED; } else { - subdev_8255_init(dev, dev->subdevices + i, NULL, - iobase); + ret = subdev_8255_init(dev, s, NULL, iobase); + if (ret) + return ret; } } - printk("\n"); - return 0; } -static int dev_8255_detach(struct comedi_device *dev) +static void dev_8255_detach(struct comedi_device *dev) { - int i; - unsigned long iobase; struct comedi_subdevice *s; - - printk(KERN_INFO "comedi%d: 8255: remove\n", dev->minor); + struct subdev_8255_private *spriv; + int i; for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; if (s->type != COMEDI_SUBD_UNUSED) { - iobase = CALLBACK_ARG; - release_region(iobase, _8255_SIZE); + spriv = s->private; + release_region(spriv->iobase, _8255_SIZE); } - subdev_8255_cleanup(dev, s); } - - return 0; } +static struct comedi_driver dev_8255_driver = { + .driver_name = "8255", + .module = THIS_MODULE, + .attach = dev_8255_attach, + .detach = dev_8255_detach, +}; +module_comedi_driver(dev_8255_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h index b6314c9b7ea..795d232a6c0 100644 --- a/drivers/staging/comedi/drivers/8255.h +++ b/drivers/staging/comedi/drivers/8255.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _8255_H @@ -27,12 +22,11 @@ #include "../comedidev.h" int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*cb) (int, int, int, unsigned long), - unsigned long arg); + int (*io)(int, int, int, unsigned long), + unsigned long iobase); int subdev_8255_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, - int (*cb) (int, int, int, unsigned long), - unsigned long arg); -void subdev_8255_cleanup(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); diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c new file mode 100644 index 00000000000..46a385c29ba --- /dev/null +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -0,0 +1,329 @@ +/* + * COMEDI driver for generic PCI based 8255 digital i/o boards + * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on the tested adl_pci7296 driver written by: + * Jon Grierson <jd@renko.co.uk> + * and the experimental cb_pcidio driver written by: + * Yoshiya Matsuzaka + * + * 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: 8255_pci +Description: Generic PCI based 8255 Digital I/O boards +Devices: (ADLink) PCI-7224 [adl_pci-7224] - 24 channels + (ADLink) PCI-7248 [adl_pci-7248] - 48 channels + (ADLink) PCI-7296 [adl_pci-7296] - 96 channels + (Measurement Computing) PCI-DIO24 [cb_pci-dio24] - 24 channels + (Measurement Computing) PCI-DIO24H [cb_pci-dio24h] - 24 channels + (Measurement Computing) PCI-DIO48H [cb_pci-dio48h] - 48 channels + (Measurement Computing) PCI-DIO96H [cb_pci-dio96h] - 96 channels + (National Instruments) PCI-DIO-96 [ni_pci-dio-96] - 96 channels + (National Instruments) PCI-DIO-96B [ni_pci-dio-96b] - 96 channels + (National Instruments) PXI-6508 [ni_pxi-6508] - 96 channels + (National Instruments) PCI-6503 [ni_pci-6503] - 24 channels + (National Instruments) PCI-6503B [ni_pci-6503b] - 24 channels + (National Instruments) PCI-6503X [ni_pci-6503x] - 24 channels + (National Instruments) PXI-6503 [ni_pxi-6503] - 24 channels +Author: H Hartley Sweeten <hsweeten@visionengravers.com> +Updated: Wed, 12 Sep 2012 11:52:01 -0700 +Status: untested + +Some of these boards also have an 8254 programmable timer/counter +chip. This chip is not currently supported by this driver. + +Interrupt support for these boards is also not currently supported. + +Configuration Options: not applicable, uses PCI auto config +*/ + +#include <linux/module.h> +#include <linux/pci.h> + +#include "../comedidev.h" + +#include "8255.h" +#include "mite.h" + +enum pci_8255_boardid { + BOARD_ADLINK_PCI7224, + BOARD_ADLINK_PCI7248, + BOARD_ADLINK_PCI7296, + BOARD_CB_PCIDIO24, + BOARD_CB_PCIDIO24H, + BOARD_CB_PCIDIO48H_OLD, + BOARD_CB_PCIDIO48H_NEW, + BOARD_CB_PCIDIO96H, + BOARD_NI_PCIDIO96, + BOARD_NI_PCIDIO96B, + BOARD_NI_PXI6508, + BOARD_NI_PCI6503, + BOARD_NI_PCI6503B, + BOARD_NI_PCI6503X, + BOARD_NI_PXI_6503, +}; + +struct pci_8255_boardinfo { + const char *name; + int dio_badr; + int n_8255; + unsigned int has_mite:1; +}; + +static const struct pci_8255_boardinfo pci_8255_boards[] = { + [BOARD_ADLINK_PCI7224] = { + .name = "adl_pci-7224", + .dio_badr = 2, + .n_8255 = 1, + }, + [BOARD_ADLINK_PCI7248] = { + .name = "adl_pci-7248", + .dio_badr = 2, + .n_8255 = 2, + }, + [BOARD_ADLINK_PCI7296] = { + .name = "adl_pci-7296", + .dio_badr = 2, + .n_8255 = 4, + }, + [BOARD_CB_PCIDIO24] = { + .name = "cb_pci-dio24", + .dio_badr = 2, + .n_8255 = 1, + }, + [BOARD_CB_PCIDIO24H] = { + .name = "cb_pci-dio24h", + .dio_badr = 2, + .n_8255 = 1, + }, + [BOARD_CB_PCIDIO48H_OLD] = { + .name = "cb_pci-dio48h", + .dio_badr = 1, + .n_8255 = 2, + }, + [BOARD_CB_PCIDIO48H_NEW] = { + .name = "cb_pci-dio48h", + .dio_badr = 2, + .n_8255 = 2, + }, + [BOARD_CB_PCIDIO96H] = { + .name = "cb_pci-dio96h", + .dio_badr = 2, + .n_8255 = 4, + }, + [BOARD_NI_PCIDIO96] = { + .name = "ni_pci-dio-96", + .dio_badr = 1, + .n_8255 = 4, + .has_mite = 1, + }, + [BOARD_NI_PCIDIO96B] = { + .name = "ni_pci-dio-96b", + .dio_badr = 1, + .n_8255 = 4, + .has_mite = 1, + }, + [BOARD_NI_PXI6508] = { + .name = "ni_pxi-6508", + .dio_badr = 1, + .n_8255 = 4, + .has_mite = 1, + }, + [BOARD_NI_PCI6503] = { + .name = "ni_pci-6503", + .dio_badr = 1, + .n_8255 = 1, + .has_mite = 1, + }, + [BOARD_NI_PCI6503B] = { + .name = "ni_pci-6503b", + .dio_badr = 1, + .n_8255 = 1, + .has_mite = 1, + }, + [BOARD_NI_PCI6503X] = { + .name = "ni_pci-6503x", + .dio_badr = 1, + .n_8255 = 1, + .has_mite = 1, + }, + [BOARD_NI_PXI_6503] = { + .name = "ni_pxi-6503", + .dio_badr = 1, + .n_8255 = 1, + .has_mite = 1, + }, +}; + +struct pci_8255_private { + void __iomem *mmio_base; +}; + +static int pci_8255_mite_init(struct pci_dev *pcidev) +{ + void __iomem *mite_base; + u32 main_phys_addr; + + /* ioremap the MITE registers (BAR 0) temporarily */ + mite_base = pci_ioremap_bar(pcidev, 0); + if (!mite_base) + return -ENOMEM; + + /* set data window to main registers (BAR 1) */ + main_phys_addr = pci_resource_start(pcidev, 1); + writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR); + + /* finished with MITE registers */ + iounmap(mite_base); + return 0; +} + +static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase) +{ + void __iomem *mmio_base = (void __iomem *)iobase; + + if (dir) { + writeb(data, mmio_base + port); + return 0; + } else { + 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 pci_8255_private *devpriv; + struct comedi_subdevice *s; + bool is_mmio; + int ret; + int i; + + if (context < ARRAY_SIZE(pci_8255_boards)) + board = &pci_8255_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + if (board->has_mite) { + ret = pci_8255_mite_init(pcidev); + if (ret) + return ret; + } + + is_mmio = (pci_resource_flags(pcidev, board->dio_badr) & + IORESOURCE_MEM) != 0; + if (is_mmio) { + devpriv->mmio_base = pci_ioremap_bar(pcidev, board->dio_badr); + if (!devpriv->mmio_base) + return -ENOMEM; + } else { + dev->iobase = pci_resource_start(pcidev, board->dio_badr); + } + + /* + * One, two, or four subdevices are setup by this driver depending + * on the number of channels provided by the board. Each subdevice + * has 24 channels supported by the 8255 module. + */ + ret = comedi_alloc_subdevices(dev, board->n_8255); + if (ret) + return ret; + + for (i = 0; i < board->n_8255; i++) { + unsigned long iobase; + + s = &dev->subdevices[i]; + if (is_mmio) { + iobase = (unsigned long)(devpriv->mmio_base + (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 (ret) + return ret; + } + + return 0; +} + +static void pci_8255_detach(struct comedi_device *dev) +{ + struct pci_8255_private *devpriv = dev->private; + + if (devpriv && devpriv->mmio_base) + iounmap(devpriv->mmio_base); + 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, +}; + +static int pci_8255_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &pci_8255_driver, id->driver_data); +} + +static const struct pci_device_id pci_8255_pci_table[] = { + { PCI_VDEVICE(ADLINK, 0x7224), BOARD_ADLINK_PCI7224 }, + { PCI_VDEVICE(ADLINK, 0x7248), BOARD_ADLINK_PCI7248 }, + { PCI_VDEVICE(ADLINK, 0x7296), BOARD_ADLINK_PCI7296 }, + { PCI_VDEVICE(CB, 0x0028), BOARD_CB_PCIDIO24 }, + { PCI_VDEVICE(CB, 0x0014), BOARD_CB_PCIDIO24H }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, 0x0000, 0x0000), + .driver_data = BOARD_CB_PCIDIO48H_OLD }, + { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, PCI_VENDOR_ID_CB, 0x000b), + .driver_data = BOARD_CB_PCIDIO48H_NEW }, + { PCI_VDEVICE(CB, 0x0017), BOARD_CB_PCIDIO96H }, + { PCI_VDEVICE(NI, 0x0160), BOARD_NI_PCIDIO96 }, + { PCI_VDEVICE(NI, 0x1630), BOARD_NI_PCIDIO96B }, + { PCI_VDEVICE(NI, 0x13c0), BOARD_NI_PXI6508 }, + { PCI_VDEVICE(NI, 0x0400), BOARD_NI_PCI6503 }, + { PCI_VDEVICE(NI, 0x1250), BOARD_NI_PCI6503B }, + { PCI_VDEVICE(NI, 0x17d0), BOARD_NI_PCI6503X }, + { PCI_VDEVICE(NI, 0x1800), BOARD_NI_PXI_6503 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, pci_8255_pci_table); + +static struct pci_driver pci_8255_pci_driver = { + .name = "8255_pci", + .id_table = pci_8255_pci_table, + .probe = pci_8255_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(pci_8255_driver, pci_8255_pci_driver); + +MODULE_DESCRIPTION("COMEDI - Generic PCI based 8255 Digital I/O boards"); +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 354fb7d2984..0757a82ddcf 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -1,8 +1,8 @@ # Makefile for individual comedi drivers # +ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG # Comedi "helper" modules -obj-$(CONFIG_COMEDI) += pcm_common.o # Comedi misc drivers obj-$(CONFIG_COMEDI_BOND) += comedi_bond.o @@ -12,20 +12,21 @@ obj-$(CONFIG_COMEDI_SERIAL2002) += serial2002.o obj-$(CONFIG_COMEDI_SKEL) += skel.o # Comedi ISA drivers -obj-$(CONFIG_COMEDI_ACL7225B) += acl7225b.o +obj-$(CONFIG_COMEDI_AMPLC_DIO200_ISA) += amplc_dio200.o +obj-$(CONFIG_COMEDI_AMPLC_PC263_ISA) += amplc_pc263.o obj-$(CONFIG_COMEDI_PCL711) += pcl711.o obj-$(CONFIG_COMEDI_PCL724) += pcl724.o -obj-$(CONFIG_COMEDI_PCL725) += pcl725.o obj-$(CONFIG_COMEDI_PCL726) += pcl726.o obj-$(CONFIG_COMEDI_PCL730) += pcl730.o obj-$(CONFIG_COMEDI_PCL812) += pcl812.o obj-$(CONFIG_COMEDI_PCL816) += pcl816.o obj-$(CONFIG_COMEDI_PCL818) += pcl818.o obj-$(CONFIG_COMEDI_PCM3724) += pcm3724.o -obj-$(CONFIG_COMEDI_PCM3730) += pcm3730.o obj-$(CONFIG_COMEDI_RTI800) += rti800.o obj-$(CONFIG_COMEDI_RTI802) += rti802.o +obj-$(CONFIG_COMEDI_DAC02) += dac02.o obj-$(CONFIG_COMEDI_DAS16M1) += das16m1.o +obj-$(CONFIG_COMEDI_DAS08_ISA) += das08_isa.o obj-$(CONFIG_COMEDI_DAS16) += das16.o obj-$(CONFIG_COMEDI_DAS800) += das800.o obj-$(CONFIG_COMEDI_DAS1800) += das1800.o @@ -40,6 +41,7 @@ obj-$(CONFIG_COMEDI_DMM32AT) += dmm32at.o obj-$(CONFIG_COMEDI_FL512) += fl512.o obj-$(CONFIG_COMEDI_AIO_AIO12_8) += aio_aio12_8.o obj-$(CONFIG_COMEDI_AIO_IIRO_16) += aio_iiro_16.o +obj-$(CONFIG_COMEDI_II_PCI20KC) += ii_pci20kc.o obj-$(CONFIG_COMEDI_C6XDIGIO) += c6xdigio.o obj-$(CONFIG_COMEDI_MPC624) += mpc624.o obj-$(CONFIG_COMEDI_ADQ12B) += adq12b.o @@ -52,51 +54,49 @@ obj-$(CONFIG_COMEDI_PCMDA12) += pcmda12.o obj-$(CONFIG_COMEDI_PCMMIO) += pcmmio.o obj-$(CONFIG_COMEDI_PCMUIO) += pcmuio.o obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o -obj-$(CONFIG_COMEDI_POC) += poc.o +obj-$(CONFIG_COMEDI_S526) += s526.o # Comedi PCI drivers -obj-$(CONFIG_COMEDI_PCI_DRIVERS) += 8255.o +obj-$(CONFIG_COMEDI_8255_PCI) += 8255_pci.o +obj-$(CONFIG_COMEDI_ADDI_WATCHDOG) += addi_watchdog.o obj-$(CONFIG_COMEDI_ADDI_APCI_035) += addi_apci_035.o obj-$(CONFIG_COMEDI_ADDI_APCI_1032) += addi_apci_1032.o obj-$(CONFIG_COMEDI_ADDI_APCI_1500) += addi_apci_1500.o obj-$(CONFIG_COMEDI_ADDI_APCI_1516) += addi_apci_1516.o obj-$(CONFIG_COMEDI_ADDI_APCI_1564) += addi_apci_1564.o obj-$(CONFIG_COMEDI_ADDI_APCI_16XX) += addi_apci_16xx.o -obj-$(CONFIG_COMEDI_ADDI_APCI_2016) += addi_apci_2016.o obj-$(CONFIG_COMEDI_ADDI_APCI_2032) += addi_apci_2032.o obj-$(CONFIG_COMEDI_ADDI_APCI_2200) += addi_apci_2200.o -obj-$(CONFIG_COMEDI_ADDI_APCI_3001) += addi_apci_3001.o obj-$(CONFIG_COMEDI_ADDI_APCI_3120) += addi_apci_3120.o obj-$(CONFIG_COMEDI_ADDI_APCI_3501) += addi_apci_3501.o obj-$(CONFIG_COMEDI_ADDI_APCI_3XXX) += addi_apci_3xxx.o obj-$(CONFIG_COMEDI_ADL_PCI6208) += adl_pci6208.o -obj-$(CONFIG_COMEDI_ADL_PCI7230) += adl_pci7230.o -obj-$(CONFIG_COMEDI_ADL_PCI7296) += adl_pci7296.o -obj-$(CONFIG_COMEDI_ADL_PCI7432) += adl_pci7432.o +obj-$(CONFIG_COMEDI_ADL_PCI7X3X) += adl_pci7x3x.o obj-$(CONFIG_COMEDI_ADL_PCI8164) += adl_pci8164.o obj-$(CONFIG_COMEDI_ADL_PCI9111) += adl_pci9111.o obj-$(CONFIG_COMEDI_ADL_PCI9118) += adl_pci9118.o obj-$(CONFIG_COMEDI_ADV_PCI1710) += adv_pci1710.o obj-$(CONFIG_COMEDI_ADV_PCI1723) += adv_pci1723.o +obj-$(CONFIG_COMEDI_ADV_PCI1724) += adv_pci1724.o obj-$(CONFIG_COMEDI_ADV_PCI_DIO) += adv_pci_dio.o -obj-$(CONFIG_COMEDI_AMPLC_DIO200) += amplc_dio200.o +obj-$(CONFIG_COMEDI_AMPLC_DIO200_PCI) += amplc_dio200_pci.o obj-$(CONFIG_COMEDI_AMPLC_PC236) += amplc_pc236.o -obj-$(CONFIG_COMEDI_AMPLC_PC263) += amplc_pc263.o +obj-$(CONFIG_COMEDI_AMPLC_PC263_PCI) += amplc_pci263.o obj-$(CONFIG_COMEDI_AMPLC_PCI224) += amplc_pci224.o obj-$(CONFIG_COMEDI_AMPLC_PCI230) += amplc_pci230.o obj-$(CONFIG_COMEDI_CONTEC_PCI_DIO) += contec_pci_dio.o +obj-$(CONFIG_COMEDI_DAS08_PCI) += das08_pci.o obj-$(CONFIG_COMEDI_DT3000) += dt3000.o +obj-$(CONFIG_COMEDI_DYNA_PCI10XX) += dyna_pci10xx.o obj-$(CONFIG_COMEDI_UNIOXX5) += unioxx5.o obj-$(CONFIG_COMEDI_GSC_HPDI) += gsc_hpdi.o obj-$(CONFIG_COMEDI_ICP_MULTI) += icp_multi.o -obj-$(CONFIG_COMEDI_II_PCI20KC) += ii_pci20kc.o obj-$(CONFIG_COMEDI_DAQBOARD2000) += daqboard2000.o obj-$(CONFIG_COMEDI_JR3_PCI) += jr3_pci.o obj-$(CONFIG_COMEDI_KE_COUNTER) += ke_counter.o obj-$(CONFIG_COMEDI_CB_PCIDAS64) += cb_pcidas64.o obj-$(CONFIG_COMEDI_CB_PCIDAS) += cb_pcidas.o obj-$(CONFIG_COMEDI_CB_PCIDDA) += cb_pcidda.o -obj-$(CONFIG_COMEDI_CB_PCIDIO) += cb_pcidio.o obj-$(CONFIG_COMEDI_CB_PCIMDAS) += cb_pcimdas.o obj-$(CONFIG_COMEDI_CB_PCIMDDA) += cb_pcimdda.o obj-$(CONFIG_COMEDI_ME4000) += me4000.o @@ -105,12 +105,13 @@ obj-$(CONFIG_COMEDI_NI_6527) += ni_6527.o obj-$(CONFIG_COMEDI_NI_65XX) += ni_65xx.o obj-$(CONFIG_COMEDI_NI_660X) += ni_660x.o obj-$(CONFIG_COMEDI_NI_670X) += ni_670x.o +obj-$(CONFIG_COMEDI_NI_LABPC_PCI) += ni_labpc_pci.o obj-$(CONFIG_COMEDI_NI_PCIDIO) += ni_pcidio.o obj-$(CONFIG_COMEDI_NI_PCIMIO) += ni_pcimio.o obj-$(CONFIG_COMEDI_RTD520) += rtd520.o -obj-$(CONFIG_COMEDI_S526) += s526.o obj-$(CONFIG_COMEDI_S626) += s626.o obj-$(CONFIG_COMEDI_SSV_DNP) += ssv_dnp.o +obj-$(CONFIG_COMEDI_MF6X4) += mf6x4.o # Comedi PCMCIA drivers obj-$(CONFIG_COMEDI_CB_DAS16_CS) += cb_das16_cs.o @@ -125,14 +126,17 @@ obj-$(CONFIG_COMEDI_QUATECH_DAQP_CS) += quatech_daqp_cs.o obj-$(CONFIG_COMEDI_DT9812) += dt9812.o obj-$(CONFIG_COMEDI_USBDUX) += usbdux.o obj-$(CONFIG_COMEDI_USBDUXFAST) += usbduxfast.o +obj-$(CONFIG_COMEDI_USBDUXSIGMA) += usbduxsigma.o obj-$(CONFIG_COMEDI_VMK80XX) += vmk80xx.o # Comedi NI drivers obj-$(CONFIG_COMEDI_MITE) += mite.o obj-$(CONFIG_COMEDI_NI_TIO) += ni_tio.o -obj-$(CONFIG_COMEDI_NI_TIO) += ni_tiocmd.o +obj-$(CONFIG_COMEDI_NI_TIOCMD) += ni_tiocmd.o obj-$(CONFIG_COMEDI_NI_LABPC) += ni_labpc.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_DAS08) += das08.o obj-$(CONFIG_COMEDI_FC) += comedi_fc.o diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c deleted file mode 100644 index 9def2250bb8..00000000000 --- a/drivers/staging/comedi/drivers/acl7225b.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * comedi/drivers/acl7225b.c - * Driver for Adlink NuDAQ ACL-7225b and clones - * José Luis Sánchez - */ -/* -Driver: acl7225b -Description: Adlink NuDAQ ACL-7225b & compatibles -Author: José Luis Sánchez (jsanchezv@teleline.es) -Status: testing -Devices: [Adlink] ACL-7225b (acl7225b), [ICP] P16R16DIO (p16r16dio) -*/ - -#include "../comedidev.h" - -#include <linux/ioport.h> - -#define ACL7225_SIZE 8 /* Requires 8 ioports, but only 4 are used */ -#define P16R16DIO_SIZE 4 -#define ACL7225_RIO_LO 0 /* Relays input/output low byte (R0-R7) */ -#define ACL7225_RIO_HI 1 /* Relays input/output high byte (R8-R15) */ -#define ACL7225_DI_LO 2 /* Digital input low byte (DI0-DI7) */ -#define ACL7225_DI_HI 3 /* Digital input high byte (DI8-DI15) */ - -static int acl7225b_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int acl7225b_detach(struct comedi_device *dev); - -struct boardtype { - const char *name; /* driver name */ - int io_range; /* len of I/O space */ -}; - -static const struct boardtype boardtypes[] = { - {"acl7225b", ACL7225_SIZE,}, - {"p16r16dio", P16R16DIO_SIZE,}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) -#define this_board ((const struct boardtype *)dev->board_ptr) - -static struct comedi_driver driver_acl7225b = { - .driver_name = "acl7225b", - .module = THIS_MODULE, - .attach = acl7225b_attach, - .detach = acl7225b_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct boardtype), -}; - -static int __init driver_acl7225b_init_module(void) -{ - return comedi_driver_register(&driver_acl7225b); -} - -static void __exit driver_acl7225b_cleanup_module(void) -{ - comedi_driver_unregister(&driver_acl7225b); -} - -module_init(driver_acl7225b_init_module); -module_exit(driver_acl7225b_cleanup_module); - -static int acl7225b_do_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - } - if (data[0] & 0x00ff) - outb(s->state & 0xff, dev->iobase + (unsigned long)s->private); - if (data[0] & 0xff00) - outb((s->state >> 8), - dev->iobase + (unsigned long)s->private + 1); - - data[1] = s->state; - - return 2; -} - -static int acl7225b_di_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = inb(dev->iobase + (unsigned long)s->private) | - (inb(dev->iobase + (unsigned long)s->private + 1) << 8); - - return 2; -} - -static int acl7225b_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int iobase, iorange; - - iobase = it->options[0]; - iorange = this_board->io_range; - printk(KERN_INFO "comedi%d: acl7225b: board=%s 0x%04x\n", dev->minor, - this_board->name, iobase); - if (!request_region(iobase, iorange, "acl7225b")) { - printk(KERN_ERR "comedi%d: request_region failed - I/O port conflict\n", - dev->minor); - return -EIO; - } - dev->board_name = this_board->name; - dev->iobase = iobase; - dev->irq = 0; - - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* Relays outputs */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = acl7225b_do_insn; - s->range_table = &range_digital; - s->private = (void *)ACL7225_RIO_LO; - - s = dev->subdevices + 1; - /* Relays status */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = acl7225b_di_insn; - s->range_table = &range_digital; - s->private = (void *)ACL7225_RIO_LO; - - s = dev->subdevices + 2; - /* Isolated digital inputs */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = acl7225b_di_insn; - s->range_table = &range_digital; - s->private = (void *)ACL7225_DI_LO; - - return 0; -} - -static int acl7225b_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: acl7225b: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, this_board->io_range); - - return 0; -} - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c deleted file mode 100644 index b59f2d484fd..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.c +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * 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. - */ -/* - | Description : APCI-1710 82X54 timer module | -*/ - -#include "APCI1710_82x54.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitTimer | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| unsigned char_ b_TimerMode, | -| ULONG_ ul_ReloadValue, | -| unsigned char_ b_InputClockSelection, | -| unsigned char_ b_InputClockLevel, | -| unsigned char_ b_OutputLevel, | -| unsigned char_ b_HardwareGateLevel) -int i_InsnConfig_InitTimer(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) -| -+----------------------------------------------------------------------------+ -| Task : Configure the Timer (b_TimerNbr) operating mode | -| (b_TimerMode) from selected module (b_ModulNbr). | -| You must calling this function be for you call any | -| other function witch access of the timer. | -| | -| | -| Timer mode description table | -| | -|+--------+-----------------------------+--------------+--------------------+| -||Selected+ Mode description +u_ReloadValue | Hardware gate input|| -|| mode | | description | action || -|+--------+-----------------------------+--------------+--------------------+| -|| |Mode 0 is typically used | | || -|| |for event counting. After | | || -|| |the initialisation, OUT | | || -|| |is initially low, and | | || -|| 0 |will remain low until the |Start counting| Hardware gate || -|| |counter reaches zero. | value | || -|| |OUT then goes high and | | || -|| |remains high until a new | | || -|| |count is written. See | | || -|| |"i_APCI1710_WriteTimerValue" | | || -|| |function. | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |Mode 1 is similar to mode 0 | | || -|| |except for the gate input | | || -|| 1 |action. The gate input is not|Start counting| Hardware trigger || -|| |used for enabled or disabled | value | || -|| |the timer. | | || -|| |The gate input is used for | | || -|| |triggered the timer. | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |This mode functions like a | | || -|| |divide-by-ul_ReloadValue | | || -|| |counter. It is typically used| | || -|| |to generate a real time clock| | || -|| |interrupt. OUT will initially| | || -|| 2 |be high after the | Division | Hardware gate || -|| |initialisation. When the | factor | || -|| |initial count has decremented| | || -|| |to 1, OUT goes low for one | | || -|| |CLK pule. OUT then goes high | | || -|| |again, the counter reloads | | || -|| |the initial count | | || -|| |(ul_ReloadValue) and the | | || -|| |process is repeated. | | || -|| |This action can generated a | | || -|| |interrupt. See function | | || -|| |"i_APCI1710_SetBoardInt- | | || -|| |RoutineX" | | || -|| |and "i_APCI1710_EnableTimer" | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |Mode 3 is typically used for | | || -|| |baud rate generation. This | | || -|| |mode is similar to mode 2 | | || -|| |except for the duty cycle of | | || -|| 3 |OUT. OUT will initially be | Division | Hardware gate || -|| |high after the initialisation| factor | || -|| |When half the initial count | | || -|| |(ul_ReloadValue) has expired,| | || -|| |OUT goes low for the | | || -|| |remainder of the count. The | | || -|| |mode is periodic; the | | || -|| |sequence above is repeated | | || -|| |indefinitely. | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |OUT will be initially high | | || -|| |after the initialisation. | | || -|| |When the initial count | | || -|| 4 |expires OUT will go low for |Start counting| Hardware gate || -|| |one CLK pulse and then go | value | || -|| |high again. | | || -|| |The counting sequences is | | || -|| |triggered by writing a new | | || -|| |value. See | | || -|| |"i_APCI1710_WriteTimerValue" | | || -|| |function. If a new count is | | || -|| |written during counting, | | || -|| |it will be loaded on the | | || -|| |next CLK pulse | | || -|+--------+-----------------------------+--------------+--------------------+| -|| |Mode 5 is similar to mode 4 | | || -|| |except for the gate input | | || -|| |action. The gate input is not| | || -|| 5 |used for enabled or disabled |Start counting| Hardware trigger || -|| |the timer. The gate input is | value | || -|| |used for triggered the timer.| | || -|+--------+-----------------------------+--------------+--------------------+| -| | -| | -| | -| Input clock selection table | -| | -| +--------------------------------+------------------------------------+ | -| | b_InputClockSelection | Description | | -| | parameter | | | -| +--------------------------------+------------------------------------+ | -| | APCI1710_PCI_BUS_CLOCK | For the timer input clock, the PCI | | -| | | bus clock / 4 is used. This PCI bus| | -| | | clock can be 30MHz or 33MHz. For | | -| | | Timer 0 only this selection are | | -| | | available. | | -| +--------------------------------+------------------------------------+ | -| | APCI1710_ FRONT_CONNECTOR_INPUT| Of the front connector you have the| | -| | | possibility to inject a input clock| | -| | | for Timer 1 or Timer 2. The source | | -| | | from this clock can eat the output | | -| | | clock from Timer 0 or any other | | -| | | clock source. | | -| +--------------------------------+------------------------------------+ | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to | -| configure (0 to 2) | -| unsigned char_ b_TimerMode : Timer mode selection | -| (0 to 5) | -| 0: Interrupt on terminal| -| count | -| 1: Hardware | -| retriggerable one- | -| shot | -| 2: Rate generator | -| 3: Square wave mode | -| 4: Software triggered | -| strobe | -| 5: Hardware triggered | -| strobe | -| See timer mode | -| description table. | -| ULONG_ ul_ReloadValue : Start counting value | -| or division factor | -| See timer mode | -| description table. | -| unsigned char_ b_InputClockSelection : Selection from input | -| timer clock. | -| See input clock | -| selection table. | -| unsigned char_ b_InputClockLevel : Selection from input | -| clock level. | -| 0 : Low active | -| (Input inverted) | -| 1 : High active | -| unsigned char_ b_OutputLevel, : Selection from output | -| clock level. | -| 0 : Low active | -| 1 : High active | -| (Output inverted) | -| unsigned char_ b_HardwareGateLevel : Selection from | -| hardware gate level. | -| 0 : Low active | -| (Input inverted) | -| 1 : High active | -| If you will not used | -| the hardware gate set | -| this value to 0. -|b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); - b_TimerMode = (unsigned char) data[0]; - ul_ReloadValue = (unsigned int) data[1]; - b_InputClockSelection =(unsigned char) data[2]; - b_InputClockLevel =(unsigned char) data[3]; - b_OutputLevel =(unsigned char) data[4]; - b_HardwareGateLevel =(unsigned char) data[5]; -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer mode selection is wrong | -| -6: Input timer clock selection is wrong | -| -7: Selection from input clock level is wrong | -| -8: Selection from output clock level is wrong | -| -9: Selection from hardware gate level is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - int i_ReturnValue = 0; - unsigned char b_ModulNbr; - unsigned char b_TimerNbr; - unsigned char b_TimerMode; - unsigned int ul_ReloadValue; - unsigned char b_InputClockSelection; - unsigned char b_InputClockLevel; - unsigned char b_OutputLevel; - unsigned char b_HardwareGateLevel; - - /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - unsigned int dw_Test = 0; - /* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); - b_TimerMode = (unsigned char) data[0]; - ul_ReloadValue = (unsigned int) data[1]; - b_InputClockSelection = (unsigned char) data[2]; - b_InputClockLevel = (unsigned char) data[3]; - b_OutputLevel = (unsigned char) data[4]; - b_HardwareGateLevel = (unsigned char) data[5]; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - - if (b_TimerNbr <= 2) { - /* Test the timer mode */ - if (b_TimerMode <= 5) { - /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - /* Test te imput clock selection */ - /* - if (((b_TimerNbr == 0) && (b_InputClockSelection == 0)) || - ((b_TimerNbr != 0) && ((b_InputClockSelection == 0) || (b_InputClockSelection == 1)))) - */ - - if (((b_TimerNbr == 0) && - (b_InputClockSelection == APCI1710_PCI_BUS_CLOCK)) || - ((b_TimerNbr == 0) && - (b_InputClockSelection == APCI1710_10MHZ)) || - ((b_TimerNbr != 0) && - ((b_InputClockSelection == APCI1710_PCI_BUS_CLOCK) || - (b_InputClockSelection == APCI1710_FRONT_CONNECTOR_INPUT) || - (b_InputClockSelection == APCI1710_10MHZ)))) { - /* BEGIN JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - if (((b_InputClockSelection == APCI1710_10MHZ) && - ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) >= 0x3131)) || - (b_InputClockSelection != APCI1710_10MHZ)) { - /* END JK 27.10.2003 : Add the possibility to use a 40 Mhz quartz */ - /* Test the input clock level selection */ - - if ((b_InputClockLevel == 0) || - (b_InputClockLevel == 1)) { - /* Test the output clock level selection */ - if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) { - /* Test the hardware gate level selection */ - if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) { - /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - /* Test if version > 1.1 and clock selection = 10MHz */ - if ((b_InputClockSelection == APCI1710_10MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0x0000FFFFUL) > 0x3131)) { - /* Test if 40MHz quartz on board */ - dw_Test = inl(devpriv->s_BoardInfos.ui_Address + (16 + (b_TimerNbr * 4) + (64 * b_ModulNbr))); - - dw_Test = (dw_Test >> 16) & 1; - } else { - dw_Test = 1; - } - - /* Test if detection OK */ - if (dw_Test == 1) { - /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - /* Initialisation OK */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init = 1; - - /* Save the input clock selection */ - devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockSelection = b_InputClockSelection; - - /* Save the input clock level */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_InputClockLevel = ~b_InputClockLevel & 1; - - /* Save the output level */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel = ~b_OutputLevel & 1; - - /* Save the gate level */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_HardwareGateLevel = b_HardwareGateLevel; - - /* Set the configuration word and disable the timer */ - /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - /* - devpriv->s_ModuleInfo [b_ModulNbr]. - s_82X54ModuleInfo. - s_82X54TimerInfo [b_TimerNbr]. - dw_ConfigurationWord = (unsigned int) (((b_HardwareGateLevel << 0) & 0x1) | - ((b_InputClockLevel << 1) & 0x2) | - (((~b_OutputLevel & 1) << 2) & 0x4) | - ((b_InputClockSelection << 4) & 0x10)); - */ - /* Test if 10MHz selected */ - if (b_InputClockSelection == APCI1710_10MHZ) { - b_InputClockSelection = 2; - } - - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = (unsigned int)(((b_HardwareGateLevel << 0) & 0x1) | ((b_InputClockLevel << 1) & 0x2) | (((~b_OutputLevel & 1) << 2) & 0x4) | ((b_InputClockSelection << 4) & 0x30)); - /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Initialise the 82X54 Timer */ - outl((unsigned int) b_TimerMode, devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Write the reload value */ - outl(ul_ReloadValue, devpriv->s_BoardInfos.ui_Address + 0 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - /* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - } /* if (dw_Test == 1) */ - else { - /* Input timer clock selection is wrong */ - i_ReturnValue = -6; - } /* if (dw_Test == 1) */ - /* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - } /* if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */ - else { - /* Selection from hardware gate level is wrong */ - DPRINTK("Selection from hardware gate level is wrong\n"); - i_ReturnValue = -9; - } /* if ((b_HardwareGateLevel == 0) || (b_HardwareGateLevel == 1)) */ - } /* if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */ - else { - /* Selection from output clock level is wrong */ - DPRINTK("Selection from output clock level is wrong\n"); - i_ReturnValue = -8; - } /* if ((b_OutputLevel == 0) || (b_OutputLevel == 1)) */ - } /* if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */ - else { - /* Selection from input clock level is wrong */ - DPRINTK("Selection from input clock level is wrong\n"); - i_ReturnValue = -7; - } /* if ((b_InputClockLevel == 0) || (b_InputClockLevel == 1)) */ - } else { - /* Input timer clock selection is wrong */ - DPRINTK("Input timer clock selection is wrong\n"); - i_ReturnValue = -6; - } - } else { - /* Input timer clock selection is wrong */ - DPRINTK("Input timer clock selection is wrong\n"); - i_ReturnValue = -6; - } - } /* if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */ - else { - /* Timer mode selection is wrong */ - DPRINTK("Timer mode selection is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_TimerMode >= 0) && (b_TimerMode <= 5)) */ - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableTimer | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| unsigned char_ b_InterruptEnable) -int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Enable OR Disable the Timer (b_TimerNbr) from selected module | -| (b_ModulNbr). You must calling the | -| "i_APCI1710_InitTimer" function be for you call this | -| function. If you enable the timer interrupt, the timer | -| generate a interrupt after the timer value reach | -| the zero. See function "i_APCI1710_SetBoardIntRoutineX"| -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to enable | -| (0 to 2) | -| unsigned char_ b_InterruptEnable : Enable or disable the | -| timer interrupt. | -| APCI1710_ENABLE : | -| Enable the timer interrupt | -| APCI1710_DISABLE : | -| Disable the timer interrupt| -i_ReturnValue=insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); - b_ActionType = (unsigned char) data[0]; /* enable disable */ -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer not initialised see function | -| "i_APCI1710_InitTimer" | -| -6: Interrupt parameter is wrong | -| -7: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_DummyRead; - unsigned char b_ModulNbr; - unsigned char b_TimerNbr; - unsigned char b_ActionType; - unsigned char b_InterruptEnable; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_TimerNbr = (unsigned char) CR_CHAN(insn->chanspec); - b_ActionType = (unsigned char) data[0]; /* enable disable */ - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) { - - switch (b_ActionType) { - case APCI1710_ENABLE: - b_InterruptEnable = (unsigned char) data[1]; - /* Test the interrupt selection */ - if ((b_InterruptEnable == APCI1710_ENABLE) || - (b_InterruptEnable == APCI1710_DISABLE)) { - if (b_InterruptEnable == APCI1710_ENABLE) { - - dw_DummyRead = inl(devpriv->s_BoardInfos.ui_Address + 12 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Enable the interrupt */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord | 0x8; - - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - devpriv->tsk_Current = current; /* Save the current process task structure */ - - } /* if (b_InterruptEnable == APCI1710_ENABLE) */ - else { - /* Disable the interrupt */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7; - - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Save the interrupt flag */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr)); - } /* if (b_InterruptEnable == APCI1710_ENABLE) */ - - /* Test if error occur */ - if (i_ReturnValue >= 0) { - /* Save the interrupt flag */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask | ((1 & b_InterruptEnable) << b_TimerNbr); - - /* Enable the timer */ - outl(1, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - } - } else { - /* Interrupt parameter is wrong */ - DPRINTK("\n"); - i_ReturnValue = -6; - } - break; - case APCI1710_DISABLE: - /* Test the interrupt flag */ - if (((devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask >> b_TimerNbr) & 1) == 1) { - /* Disable the interrupt */ - - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr]. dw_ConfigurationWord = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord & 0xF7; - - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].dw_ConfigurationWord, devpriv->s_BoardInfos.ui_Address + 32 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - /* Save the interrupt flag */ - devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask = devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.b_InterruptMask & (0xFF - (1 << b_TimerNbr)); - } - - /* Disable the timer */ - outl(0, devpriv->s_BoardInfos.ui_Address + 44 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - break; - } /* Switch end */ - } else { - /* Timer not initialised see function */ - DPRINTK ("Timer not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadAllTimerValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| PULONG_ pul_TimerValueArray) -int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the all timer values from selected timer | -| module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_TimerValueArray : Timer value array. | -| Element 0 contain the timer 0 value. | -| Element 1 contain the timer 1 value. | -| Element 2 contain the timer 2 value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a TIMER module | -| -4: Timer 0 not initialised see function | -| "i_APCI1710_InitTimer" | -| -5: Timer 1 not initialised see function | -| "i_APCI1710_InitTimer" | -| -6: Timer 2 not initialised see function | -| "i_APCI1710_InitTimer" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned char b_ModulNbr, b_ReadType; - unsigned int *pul_TimerValueArray; - - b_ModulNbr = CR_AREF(insn->chanspec); - b_ReadType = CR_CHAN(insn->chanspec); - pul_TimerValueArray = (unsigned int *) data; - i_ReturnValue = insn->n; - - switch (b_ReadType) { - case APCI1710_TIMER_READINTERRUPT: - - data[0] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters.s_FIFOInterruptParameters[devpriv->s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /* Increment the read FIFO */ - devpriv->s_InterruptParameters.ui_Read = (devpriv->s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - break; - - case APCI1710_TIMER_READALLTIMER: - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test if timer 0 iniutialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[0].b_82X54Init == 1) { - /* Test if timer 1 iniutialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[1].b_82X54Init == 1) { - /* Test if timer 2 iniutialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[2].b_82X54Init == 1) { - /* Latch all counter */ - outl(0x17, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); - - /* Read the timer 0 value */ - pul_TimerValueArray[0] = inl(devpriv->s_BoardInfos.ui_Address + 0 + (64 * b_ModulNbr)); - - /* Read the timer 1 value */ - pul_TimerValueArray[1] = inl(devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr)); - - /* Read the timer 2 value */ - pul_TimerValueArray[2] = inl(devpriv->s_BoardInfos.ui_Address + 8 + (64 * b_ModulNbr)); - } else { - /* Timer 2 not initialised see function */ - DPRINTK("Timer 2 not initialised see function\n"); - i_ReturnValue = -6; - } - } else { - /* Timer 1 not initialised see function */ - DPRINTK("Timer 1 not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer 0 not initialised see function */ - DPRINTK("Timer 0 not initialised see function\n"); - i_ReturnValue = -4; - } - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -3; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - } /* End of Switch */ - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnBitsTimer(struct comedi_device *dev, -struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read write functions for Timer | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnBitsTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned char b_BitsType; - int i_ReturnValue = 0; - b_BitsType = data[0]; - - printk("\n82X54"); - - switch (b_BitsType) { - case APCI1710_TIMER_READVALUE: - i_ReturnValue = i_APCI1710_ReadTimerValue(dev, - (unsigned char)CR_AREF(insn->chanspec), - (unsigned char)CR_CHAN(insn->chanspec), - (unsigned int *) &data[0]); - break; - - case APCI1710_TIMER_GETOUTPUTLEVEL: - i_ReturnValue = i_APCI1710_GetTimerOutputLevel(dev, - (unsigned char)CR_AREF(insn->chanspec), - (unsigned char)CR_CHAN(insn->chanspec), - (unsigned char *) &data[0]); - break; - - case APCI1710_TIMER_GETPROGRESSSTATUS: - i_ReturnValue = i_APCI1710_GetTimerProgressStatus(dev, - (unsigned char)CR_AREF(insn->chanspec), - (unsigned char)CR_CHAN(insn->chanspec), - (unsigned char *)&data[0]); - break; - - case APCI1710_TIMER_WRITEVALUE: - i_ReturnValue = i_APCI1710_WriteTimerValue(dev, - (unsigned char)CR_AREF(insn->chanspec), - (unsigned char)CR_CHAN(insn->chanspec), - (unsigned int)data[1]); - - break; - - default: - printk("Bits Config Parameter Wrong\n"); - i_ReturnValue = -1; - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadTimerValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| PULONG_ pul_TimerValue) | -+----------------------------------------------------------------------------+ -| Task : Return the timer value from selected digital timer | -| (b_TimerNbr) from selected timer module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to read | -| (0 to 2) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_TimerValue : Timer value | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer not initialised see function | -| "i_APCI1710_InitTimer" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_ReadTimerValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_TimerNbr, - unsigned int *pul_TimerValue) -{ - int i_ReturnValue = 0; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_82X54ModuleInfo. - s_82X54TimerInfo[b_TimerNbr]. - b_82X54Init == 1) { - /* Latch the timer value */ - outl((2 << b_TimerNbr) | 0xD0, - devpriv->s_BoardInfos. - ui_Address + 12 + - (64 * b_ModulNbr)); - - /* Read the counter value */ - *pul_TimerValue = - inl(devpriv->s_BoardInfos. - ui_Address + (b_TimerNbr * 4) + - (64 * b_ModulNbr)); - } else { - /* Timer not initialised see function */ - DPRINTK("Timer not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_GetTimerOutputLevel | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr, | - | unsigned char_ b_TimerNbr, | - | unsigned char *_ pb_OutputLevel) | - +----------------------------------------------------------------------------+ - | Task : Return the output signal level (pb_OutputLevel) from | - | selected digital timer (b_TimerNbr) from selected timer| - | module (b_ModulNbr). | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board | - | APCI-1710 | - | unsigned char_ b_ModulNbr : Selected module number | - | (0 to 3) | - | unsigned char_ b_TimerNbr : Timer number to test | - | (0 to 2) | - +----------------------------------------------------------------------------+ - | Output Parameters : unsigned char *_ pb_OutputLevel : Output signal level | - | 0 : The output is low | - | 1 : The output is high | - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: Module selection wrong | - | -3: Timer selection wrong | - | -4: The module is not a TIMER module | - | -5: Timer not initialised see function | - | "i_APCI1710_InitTimer" | - +----------------------------------------------------------------------------+ - */ - -int i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_TimerNbr, - unsigned char *pb_OutputLevel) -{ - int i_ReturnValue = 0; - unsigned int dw_TimerStatus; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) { - /* Latch the timer value */ - outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); - - /* Read the timer status */ - dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - *pb_OutputLevel = (unsigned char) (((dw_TimerStatus >> 7) & 1) ^ devpriv-> s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_OutputLevel); - } else { - /* Timer not initialised see function */ - DPRINTK("Timer not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetTimerProgressStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| unsigned char *_ pb_TimerStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the progress status (pb_TimerStatus) from | -| selected digital timer (b_TimerNbr) from selected timer| -| module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to test | -| (0 to 2) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TimerStatus : Output signal level | -| 0 : Timer not in progress | -| 1 : Timer in progress | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer not initialised see function | -| "i_APCI1710_InitTimer" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_TimerNbr, - unsigned char *pb_TimerStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_TimerStatus; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) { - /* Latch the timer value */ - outl((2 << b_TimerNbr) | 0xE0, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); - - /* Read the timer status */ - dw_TimerStatus = inl(devpriv->s_BoardInfos.ui_Address + 16 + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - - *pb_TimerStatus = (unsigned char) ((dw_TimerStatus) >> 8) & 1; - printk("ProgressStatus : %d", *pb_TimerStatus); - } else { - /* Timer not initialised see function */ - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - - i_ReturnValue = -4; - } - } else { - /* Module number error */ - - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_WriteTimerValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TimerNbr, | -| ULONG_ ul_WriteValue) | -+----------------------------------------------------------------------------+ -| Task : Write the value (ul_WriteValue) into the selected timer| -| (b_TimerNbr) from selected timer module (b_ModulNbr). | -| The action in depend of the time mode selection. | -| See timer mode description table. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board | -| APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_TimerNbr : Timer number to write | -| (0 to 2) | -| ULONG_ ul_WriteValue : Value to write | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: Timer selection wrong | -| -4: The module is not a TIMER module | -| -5: Timer not initialised see function | -| "i_APCI1710_InitTimer" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_WriteTimerValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_TimerNbr, - unsigned int ul_WriteValue) -{ - int i_ReturnValue = 0; - - /* Test the module number */ - if (b_ModulNbr < 4) { - /* Test if 82X54 timer */ - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - /* Test the timer number */ - if (b_TimerNbr <= 2) { - /* Test if timer initialised */ - if (devpriv->s_ModuleInfo[b_ModulNbr].s_82X54ModuleInfo.s_82X54TimerInfo[b_TimerNbr].b_82X54Init == 1) { - /* Write the value */ - outl(ul_WriteValue, devpriv->s_BoardInfos.ui_Address + (b_TimerNbr * 4) + (64 * b_ModulNbr)); - } else { - /* Timer not initialised see function */ - DPRINTK("Timer not initialised see function\n"); - i_ReturnValue = -5; - } - } else { - /* Timer selection wrong */ - DPRINTK("Timer selection wrong\n"); - i_ReturnValue = -3; - } /* if ((b_TimerNbr >= 0) && (b_TimerNbr <= 2)) */ - } else { - /* The module is not a TIMER module */ - DPRINTK("The module is not a TIMER module\n"); - i_ReturnValue = -4; - } - } else { - /* Module number error */ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h deleted file mode 100644 index 81346dbc35f..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_82x54.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_PCI_BUS_CLOCK 0 -#define APCI1710_FRONT_CONNECTOR_INPUT 1 -#define APCI1710_TIMER_READVALUE 0 -#define APCI1710_TIMER_GETOUTPUTLEVEL 1 -#define APCI1710_TIMER_GETPROGRESSSTATUS 2 -#define APCI1710_TIMER_WRITEVALUE 3 - -#define APCI1710_TIMER_READINTERRUPT 1 -#define APCI1710_TIMER_READALLTIMER 2 - -/* BEGIN JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ -#ifndef APCI1710_10MHZ -#define APCI1710_10MHZ 10 -#endif -/* END JK 27.10.03 : Add the possibility to use a 40 Mhz quartz */ - -/* - * 82X54 TIMER INISIALISATION FUNCTION - */ -int i_APCI1710_InsnConfigInitTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnWriteEnableDisableTimer(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * 82X54 READ FUNCTION - */ -int i_APCI1710_InsnReadAllTimerValue(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnBitsTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * 82X54 READ & WRITE FUNCTION - */ -int i_APCI1710_ReadTimerValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_TimerNbr, - unsigned int *pul_TimerValue); - -int i_APCI1710_GetTimerOutputLevel(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_TimerNbr, - unsigned char *pb_OutputLevel); - -int i_APCI1710_GetTimerProgressStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_TimerNbr, - unsigned char *pb_TimerStatus); - -/* - * 82X54 WRITE FUNCTION - */ -int i_APCI1710_WriteTimerValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_TimerNbr, - unsigned int ul_WriteValue); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c deleted file mode 100644 index 482a412aa65..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.c +++ /dev/null @@ -1,2031 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : CHRONO.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 chronometer module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 29/06/98 | S. Weber | Digital input / output implementation | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ - | | | | - | | | | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ -#include "APCI1710_Chrono.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitChrono | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_ChronoMode, | -| unsigned char_ b_PCIInputClock, | -| unsigned char_ b_TimingUnit, | -| ULONG_ ul_TimingInterval, | -| PULONG_ pul_RealTimingInterval) - -+----------------------------------------------------------------------------+ -| Task : Configure the chronometer operating mode (b_ChronoMode)| -| from selected module (b_ModulNbr). | -| The ul_TimingInterval and ul_TimingUnit determine the | -| timing base for the measurement. | -| The pul_RealTimingInterval return the real timing | -| value. You must calling this function be for you call | -| any other function witch access of the chronometer. | -| | -| Witch this functionality from the APCI-1710 you have | -| the possibility to measure the timing witch two event. | -| | -| The mode 0 and 1 is appropriate for period measurement.| -| The mode 2 and 3 is appropriate for frequent | -| measurement. | -| The mode 4 to 7 is appropriate for measuring the timing| -| between two event. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr CR_AREF(insn->chanspec) : Module number to configure | -| (0 to 3) | -| unsigned char_ b_ChronoMode data[0] : Chronometer action mode | -| (0 to 7). | -| unsigned char_ b_PCIInputClock data[1] : Selection from PCI bus clock| -| - APCI1710_30MHZ : | -| The PC have a PCI bus | -| clock from 30 MHz | -| - APCI1710_33MHZ : | -| The PC have a PCI bus | -| clock from 33 MHz | -| - APCI1710_40MHZ | -| The APCI-1710 have a | -| integrated 40Mhz | -| quartz. | -| unsigned char_ b_TimingUnit data[2] : Base timing unity (0 to 4) | -| 0 : ns | -| 1 : µs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| ULONG_ ul_TimingInterval : data[3] Base timing value. | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_RealTimingInterval : Real base timing | -| value. -| data[0] -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer mode selection is wrong | -| -5: The selected PCI input clock is wrong | -| -6: Timing unity selection is wrong | -| -7: Base timing selection is wrong | -| -8: You can not used the 40MHz clock selection with | -| this board | -| -9: You can not used the 40MHz clock selection with | -| this CHRONOS version | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int ul_TimerValue = 0; - unsigned int ul_TimingInterval = 0; - unsigned int ul_RealTimingInterval = 0; - double d_RealTimingInterval = 0; - unsigned int dw_ModeArray[8] = - { 0x01, 0x05, 0x00, 0x04, 0x02, 0x0E, 0x0A, 0x06 }; - unsigned char b_ModulNbr, b_ChronoMode, b_PCIInputClock, b_TimingUnit; - - b_ModulNbr = CR_AREF(insn->chanspec); - b_ChronoMode = (unsigned char) data[0]; - b_PCIInputClock = (unsigned char) data[1]; - b_TimingUnit = (unsigned char) data[2]; - ul_TimingInterval = (unsigned int) data[3]; - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /*****************************/ - /* Test the chronometer mode */ - /*****************************/ - - if (b_ChronoMode <= 7) { - /**************************/ - /* Test the PCI bus clock */ - /**************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ) || - (b_PCIInputClock == APCI1710_33MHZ) || - (b_PCIInputClock == APCI1710_40MHZ)) { - /*************************/ - /* Test the timing unity */ - /*************************/ - - if (b_TimingUnit <= 4) { - /**********************************/ - /* Test the base timing selection */ - /**********************************/ - - if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 66) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165576UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143165UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 143UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 60) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150240UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130150UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 130UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 2UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 50) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374182UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107374UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 107UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 1UL))) { - /**************************/ - /* Test the board version */ - /**************************/ - - if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) { - /************************/ - /* Test the TOR version */ - /************************/ - - if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || (b_PCIInputClock != APCI1710_40MHZ)) { - fpu_begin - (); - - /****************************************/ - /* Calculate the timer 0 division fator */ - /****************************************/ - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.001 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.001 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.001 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (0.001 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.001 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (1.0 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (1.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (1.0 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - ( - (double) - 1.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (1.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - ul_TimingInterval - * - (1000 - * - b_PCIInputClock); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (1000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (1000.0 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (1000.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (1000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (1000000.0 - * - b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (1000000.0 - * - (double) - b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (1000000.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - ( - (ul_TimingInterval - * - 60) - * - (1000000.0 - * - b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_TimingInterval * 60.0) * (1000000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (1000000.0 - * - (double) - b_PCIInputClock)) - / - 60; - d_RealTimingInterval - = - ( - (double) - ul_TimerValue - / - (0.001 * (double)b_PCIInputClock)) / 60.0; - - if ((double)(((double)ul_TimerValue / (1000000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 0.99392); - } - - break; - } - - fpu_end(); - - /****************************/ - /* Save the PCI input clock */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_PCIInputClock - = - b_PCIInputClock; - - /*************************/ - /* Save the timing unity */ - /*************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_TimingUnit - = - b_TimingUnit; - - /************************/ - /* Save the base timing */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - d_TimingInterval - = - d_RealTimingInterval; - - /****************************/ - /* Set the chronometer mode */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg - = - dw_ModeArray - [b_ChronoMode]; - - /***********************/ - /* Test if 40 MHz used */ - /***********************/ - - if (b_PCIInputClock == APCI1710_40MHZ) { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg - | - 0x80; - } - - outl(devpriv->s_ModuleInfo[b_ModulNbr].s_ChronoModuleInfo.dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 16 + (64 * b_ModulNbr)); - - /***********************/ - /* Write timer 0 value */ - /***********************/ - - outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr)); - - /*********************/ - /* Chronometer init. */ - /*********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_ChronoInit - = - 1; - } else { - /***********************************************/ - /* TOR version error for 40MHz clock selection */ - /***********************************************/ - - DPRINTK("TOR version error for 40MHz clock selection\n"); - i_ReturnValue - = - -9; - } - } else { - /**************************************************************/ - /* You can not use the 40MHz clock selection with this board */ - /**************************************************************/ - - DPRINTK("You can not used the 40MHz clock selection with this board\n"); - i_ReturnValue = - -8; - } - } else { - /**********************************/ - /* Base timing selection is wrong */ - /**********************************/ - - DPRINTK("Base timing selection is wrong\n"); - i_ReturnValue = -7; - } - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - else { - /***********************************/ - /* Timing unity selection is wrong */ - /***********************************/ - - DPRINTK("Timing unity selection is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ - else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ - } /* if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */ - else { - /***************************************/ - /* Chronometer mode selection is wrong */ - /***************************************/ - - DPRINTK("Chronometer mode selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_ChronoMode >= 0 && b_ChronoMode <= 7) */ - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - data[0] = ul_RealTimingInterval; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableChrono | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_CycleMode, | -| unsigned char_ b_InterruptEnable) -int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, -struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Enable the chronometer from selected module | -| (b_ModulNbr). You must calling the | -| "i_APCI1710_InitChrono" function be for you call this | -| function. | -| If you enable the chronometer interrupt, the | -| chronometer generate a interrupt after the stop signal.| -| See function "i_APCI1710_SetBoardIntRoutineX" and the | -| Interrupt mask description chapter from this manual. | -| The b_CycleMode parameter determine if you will | -| measured a single or more cycle. - -| Disable the chronometer from selected module | -| (b_ModulNbr). If you disable the chronometer after a | -| start signal occur and you restart the chronometer | -| witch the " i_APCI1710_EnableChrono" function, if no | -| stop signal occur this start signal is ignored. -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr CR_AREF(chanspec) : Selected module number (0 to 3) | - data[0] ENABle/Disable chrono -| unsigned char_ b_CycleMode : Selected the chronometer | -| data[1] acquisition mode | -| unsigned char_ b_InterruptEnable : Enable or disable the | -| data[2] chronometer interrupt. | -| APCI1710_ENABLE: | -| Enable the chronometer | -| interrupt | -| APCI1710_DISABLE: | -| Disable the chronometer | -| interrupt | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -| -5: Chronometer acquisition mode cycle is wrong | -| -6: Interrupt parameter is wrong | -| -7: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" - -8: data[0] wrong input | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned char b_ModulNbr, b_CycleMode, b_InterruptEnable, b_Action; - b_ModulNbr = CR_AREF(insn->chanspec); - b_Action = (unsigned char) data[0]; - b_CycleMode = (unsigned char) data[1]; - b_InterruptEnable = (unsigned char) data[2]; - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - - switch (b_Action) { - - case APCI1710_ENABLE: - - /*********************************/ - /* Test the cycle mode parameter */ - /*********************************/ - - if ((b_CycleMode == APCI1710_SINGLE) - || (b_CycleMode == - APCI1710_CONTINUOUS)) { - /***************************/ - /* Test the interrupt flag */ - /***************************/ - - if ((b_InterruptEnable == - APCI1710_ENABLE) - || (b_InterruptEnable == - APCI1710_DISABLE)) - { - - /***************************/ - /* Save the interrupt flag */ - /***************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_InterruptMask - = - b_InterruptEnable; - - /***********************/ - /* Save the cycle mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_CycleMode = - b_CycleMode; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg & - 0x8F) | ((1 & - b_InterruptEnable) - << 5) | ((1 & - b_CycleMode) - << 6) | 0x10; - - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if (b_InterruptEnable == - APCI1710_ENABLE) - { - /****************************/ - /* Clear the interrupt flag */ - /****************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg, - devpriv-> - s_BoardInfos. - ui_Address - + 32 + - (64 * b_ModulNbr)); - devpriv->tsk_Current = current; /* Save the current process task structure */ - } - - /***********************************/ - /* Enable or disable the interrupt */ - /* Enable the chronometer */ - /***********************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg, - devpriv-> - s_BoardInfos. - ui_Address + - 16 + - (64 * b_ModulNbr)); - - /*************************/ - /* Clear status register */ - /*************************/ - - outl(0, devpriv-> - s_BoardInfos. - ui_Address + - 36 + - (64 * b_ModulNbr)); - - } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ - else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ - } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ - else { - /***********************************************/ - /* Chronometer acquisition mode cycle is wrong */ - /***********************************************/ - - DPRINTK("Chronometer acquisition mode cycle is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ - break; - - case APCI1710_DISABLE: - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo. - b_InterruptMask = 0; - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo. - dw_ConfigReg & 0x2F; - - /***************************/ - /* Disable the interrupt */ - /* Disable the chronometer */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.dw_ConfigReg, - devpriv->s_BoardInfos. - ui_Address + 16 + - (64 * b_ModulNbr)); - - /***************************/ - /* Test if continuous mode */ - /***************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo. - b_CycleMode == - APCI1710_CONTINUOUS) { - /*************************/ - /* Clear status register */ - /*************************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 36 + - (64 * b_ModulNbr)); - } - break; - - default: - DPRINTK("Inputs wrong! Enable or Disable chrono\n"); - i_ReturnValue = -8; - } /* switch ENABLE/DISABLE */ - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnReadChrono(struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read functions for Timer | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnReadChrono(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned char b_ReadType; - int i_ReturnValue = insn->n; - - b_ReadType = CR_CHAN(insn->chanspec); - - switch (b_ReadType) { - case APCI1710_CHRONO_PROGRESS_STATUS: - i_ReturnValue = i_APCI1710_GetChronoProgressStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_CHRONO_READVALUE: - i_ReturnValue = i_APCI1710_ReadChronoValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned int) insn->unused[0], - (unsigned char *) &data[0], (unsigned int *) &data[1]); - break; - - case APCI1710_CHRONO_CONVERTVALUE: - i_ReturnValue = i_APCI1710_ConvertChronoValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned int) insn->unused[0], - (unsigned int *) &data[0], - (unsigned char *) &data[1], - (unsigned char *) &data[2], - (unsigned int *) &data[3], - (unsigned int *) &data[4], (unsigned int *) &data[5]); - break; - - case APCI1710_CHRONO_READINTERRUPT: - printk("In Chrono Read Interrupt\n"); - - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /**************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv-> - s_InterruptParameters. - ui_Read = (devpriv-> - s_InterruptParameters. - ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - break; - - default: - printk("ReadType Parameter wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; - -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetChronoProgressStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_ChronoStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the chronometer status (pb_ChronoStatus) from | -| selected chronometer module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pb_ChronoStatus : Return the chronometer | -| status. | -| 0 : Measurement not started.| -| No start signal occur. | -| 1 : Measurement started. | -| A start signal occur. | -| 2 : Measurement stopped. | -| A stop signal occur. | -| The measurement is | -| terminate. | -| 3: A overflow occur. You | -| must change the base | -| timing witch the | -| function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_ChronoStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (64 * b_ModulNbr)); - - /********************/ - /* Test if overflow */ - /********************/ - - if ((dw_Status & 8) == 8) { - /******************/ - /* Overflow occur */ - /******************/ - - *pb_ChronoStatus = 3; - } /* if ((dw_Status & 8) == 8) */ - else { - /*******************************/ - /* Test if measurement stopped */ - /*******************************/ - - if ((dw_Status & 2) == 2) { - /***********************/ - /* A stop signal occur */ - /***********************/ - - *pb_ChronoStatus = 2; - } /* if ((dw_Status & 2) == 2) */ - else { - /*******************************/ - /* Test if measurement started */ - /*******************************/ - - if ((dw_Status & 1) == 1) { - /************************/ - /* A start signal occur */ - /************************/ - - *pb_ChronoStatus = 1; - } /* if ((dw_Status & 1) == 1) */ - else { - /***************************/ - /* Measurement not started */ - /***************************/ - - *pb_ChronoStatus = 0; - } /* if ((dw_Status & 1) == 1) */ - } /* if ((dw_Status & 2) == 2) */ - } /* if ((dw_Status & 8) == 8) */ - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadChronoValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned int_ ui_TimeOut, | -| unsigned char *_ pb_ChronoStatus, | -| PULONG_ pul_ChronoValue) | -+----------------------------------------------------------------------------+ -| Task : Return the chronometer status (pb_ChronoStatus) and the| -| timing value (pul_ChronoValue) after a stop signal | -| occur from selected chronometer module (b_ModulNbr). | -| This function are only avaible if you have disabled | -| the interrupt functionality. See function | -| "i_APCI1710_EnableChrono" and the Interrupt mask | -| description chapter. | -| You can test the chronometer status witch the | -| "i_APCI1710_GetChronoProgressStatus" function. | -| | -| The returned value from pul_ChronoValue parameter is | -| not real measured timing. | -| You must used the "i_APCI1710_ConvertChronoValue" | -| function or make this operation for calculate the | -| timing: | -| | -| Timing = pul_ChronoValue * pul_RealTimingInterval. | -| | -| pul_RealTimingInterval is the returned parameter from | -| "i_APCI1710_InitChrono" function and the time unity is | -| the b_TimingUnit from "i_APCI1710_InitChrono" function| -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pb_ChronoStatus : Return the chronometer | -| status. | -| 0 : Measurement not started.| -| No start signal occur. | -| 1 : Measurement started. | -| A start signal occur. | -| 2 : Measurement stopped. | -| A stop signal occur. | -| The measurement is | -| terminate. | -| 3: A overflow occur. You | -| must change the base | -| timing witch the | -| function | -| "i_APCI1710_InitChrono" | -| unsigned int * pul_ChronoValue : Chronometer timing value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -| -5: Timeout parameter is wrong (0 to 65535) | -| -6: Interrupt routine installed. You can not read | -| directly the chronometer measured timing. | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_ReadChronoValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int ui_TimeOut, unsigned char *pb_ChronoStatus, unsigned int *pul_ChronoValue) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_TimeOut = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - /*****************************/ - /* Test the timout parameter */ - /*****************************/ - - if (ui_TimeOut <= 65535UL) { - - for (;;) { - /*******************/ - /* Read the status */ - /*******************/ - - dw_Status = - inl(devpriv-> - s_BoardInfos. - ui_Address + 8 + - (64 * b_ModulNbr)); - - /********************/ - /* Test if overflow */ - /********************/ - - if ((dw_Status & 8) == 8) { - /******************/ - /* Overflow occur */ - /******************/ - - *pb_ChronoStatus = 3; - - /***************************/ - /* Test if continuous mode */ - /***************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_CycleMode == - APCI1710_CONTINUOUS) - { - /*************************/ - /* Clear status register */ - /*************************/ - - outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr)); - } - - break; - } /* if ((dw_Status & 8) == 8) */ - else { - /*******************************/ - /* Test if measurement stopped */ - /*******************************/ - - if ((dw_Status & 2) == - 2) { - /***********************/ - /* A stop signal occur */ - /***********************/ - - *pb_ChronoStatus - = 2; - - /***************************/ - /* Test if continnous mode */ - /***************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_ChronoModuleInfo. - b_CycleMode - == - APCI1710_CONTINUOUS) - { - /*************************/ - /* Clear status register */ - /*************************/ - - outl(0, devpriv->s_BoardInfos.ui_Address + 36 + (64 * b_ModulNbr)); - } - break; - } /* if ((dw_Status & 2) == 2) */ - else { - /*******************************/ - /* Test if measurement started */ - /*******************************/ - - if ((dw_Status & 1) == 1) { - /************************/ - /* A start signal occur */ - /************************/ - - *pb_ChronoStatus - = - 1; - } /* if ((dw_Status & 1) == 1) */ - else { - /***************************/ - /* Measurement not started */ - /***************************/ - - *pb_ChronoStatus - = - 0; - } /* if ((dw_Status & 1) == 1) */ - } /* if ((dw_Status & 2) == 2) */ - } /* if ((dw_Status & 8) == 8) */ - - if (dw_TimeOut == ui_TimeOut) { - /*****************/ - /* Timeout occur */ - /*****************/ - - break; - } else { - /*************************/ - /* Increment the timeout */ - /*************************/ - - dw_TimeOut = - dw_TimeOut + 1; - mdelay(1000); - - } - } /* for (;;) */ - - /*****************************/ - /* Test if stop signal occur */ - /*****************************/ - - if (*pb_ChronoStatus == 2) { - /**********************************/ - /* Read the measured timing value */ - /**********************************/ - - *pul_ChronoValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 4 + - (64 * b_ModulNbr)); - - if (*pul_ChronoValue != 0) { - *pul_ChronoValue = - *pul_ChronoValue - - 1; - } - } else { - /*************************/ - /* Test if timeout occur */ - /*************************/ - - if ((*pb_ChronoStatus != 3) - && (dw_TimeOut == - ui_TimeOut) - && (ui_TimeOut != 0)) { - /*****************/ - /* Timeout occur */ - /*****************/ - - *pb_ChronoStatus = 4; - } - } - - } else { - /******************************/ - /* Timeout parameter is wrong */ - /******************************/ - DPRINTK("Timeout parameter is wrong\n"); - i_ReturnValue = -5; - } - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ConvertChronoValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| ULONG_ ul_ChronoValue, | -| PULONG_ pul_Hour, | -| unsigned char *_ pb_Minute, | -| unsigned char *_ pb_Second, | -| unsigned int *_ pui_MilliSecond, | -| unsigned int *_ pui_MicroSecond, | -| unsigned int *_ pui_NanoSecond) | -+----------------------------------------------------------------------------+ -| Task : Convert the chronometer measured timing | -| (ul_ChronoValue) in to h, mn, s, ms, µs, ns. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -| ULONG_ ul_ChronoValue : Measured chronometer timing | -| value. | -| See"i_APCI1710_ReadChronoValue"| -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_Hour : Chronometer timing hour | -| unsigned char *_ pb_Minute : Chronometer timing minute | -| unsigned char *_ pb_Second : Chronometer timing second | -| unsigned int *_ pui_MilliSecond : Chronometer timing mini | -| second | -| unsigned int *_ pui_MicroSecond : Chronometer timing micro | -| second | -| unsigned int *_ pui_NanoSecond : Chronometer timing nano | -| second | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_ConvertChronoValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int ul_ChronoValue, - unsigned int *pul_Hour, - unsigned char *pb_Minute, - unsigned char *pb_Second, - unsigned int *pui_MilliSecond, unsigned int *pui_MicroSecond, unsigned int *pui_NanoSecond) -{ - int i_ReturnValue = 0; - double d_Hour; - double d_Minute; - double d_Second; - double d_MilliSecond; - double d_MicroSecond; - double d_NanoSecond; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - fpu_begin(); - - d_Hour = (double)ul_ChronoValue *(double) - devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.d_TimingInterval; - - switch (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_TimingUnit) { - case 0: - d_Hour = d_Hour / (double)1000.0; - - case 1: - d_Hour = d_Hour / (double)1000.0; - - case 2: - d_Hour = d_Hour / (double)1000.0; - - case 3: - d_Hour = d_Hour / (double)60.0; - - case 4: - /**********************/ - /* Calculate the hour */ - /**********************/ - - d_Hour = d_Hour / (double)60.0; - *pul_Hour = (unsigned int) d_Hour; - - /************************/ - /* Calculate the minute */ - /************************/ - - d_Minute = d_Hour - *pul_Hour; - d_Minute = d_Minute * 60; - *pb_Minute = (unsigned char) d_Minute; - - /************************/ - /* Calculate the second */ - /************************/ - - d_Second = d_Minute - *pb_Minute; - d_Second = d_Second * 60; - *pb_Second = (unsigned char) d_Second; - - /*****************************/ - /* Calculate the mini second */ - /*****************************/ - - d_MilliSecond = d_Second - *pb_Second; - d_MilliSecond = d_MilliSecond * 1000; - *pui_MilliSecond = (unsigned int) d_MilliSecond; - - /******************************/ - /* Calculate the micro second */ - /******************************/ - - d_MicroSecond = - d_MilliSecond - - *pui_MilliSecond; - d_MicroSecond = d_MicroSecond * 1000; - *pui_MicroSecond = (unsigned int) d_MicroSecond; - - /******************************/ - /* Calculate the micro second */ - /******************************/ - - d_NanoSecond = - d_MicroSecond - - *pui_MicroSecond; - d_NanoSecond = d_NanoSecond * 1000; - *pui_NanoSecond = (unsigned int) d_NanoSecond; - break; - } - - fpu_end(); - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Sets the output witch has been passed with the | -| parameter b_Channel. Setting an output means setting an| -| output high. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -| unsigned char_ b_OutputChannel : Selection from digital output | -| CR_CHAN() channel (0 to 2) | -| 0 : Channel H | -| 1 : Channel A | -| 2 : Channel B | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: The selected digital output is wrong | -| -5: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetChronoChlOff | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_OutputChannel) | -+----------------------------------------------------------------------------+ -| Task : Resets the output witch has been passed with the | -| parameter b_Channel. Resetting an output means setting | -| an output low. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 - data[0] : Chl ON, Chl OFF , Chl Read , Port Read - -| unsigned char_ b_ModulNbr CR_AREF : Selected module number (0 to 3)| -| unsigned char_ b_OutputChannel CR_CHAN : Selection from digital output | -| channel (0 to 2) | -| 0 : Channel H | -| 1 : Channel A | -| 2 : Channel B | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: The selected digital output is wrong | -| -5: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadChronoChlValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_InputChannel, | -| unsigned char *_ pb_ChannelStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the status from selected digital input | -| (b_InputChannel) from selected chronometer | -| module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -| unsigned char_ b_InputChannel : Selection from digital input | -| channel (0 to 2) | -| CR_CHAN() 0 : Channel E | -| 1 : Channel F | -| 2 : Channel G | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel status.| -| data[0] 0 : Channel is not active | -| 1 : Channel is active | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: The selected digital input is wrong | -| -5: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadChronoPortValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_PortValue) | -+----------------------------------------------------------------------------+ -| Task : Return the status from digital inputs port from | -| selected (b_ModulNbr) chronometer module. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_PortValue : Digital inputs port status. -| data[0] -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a Chronometer module | -| -4: Chronometer not initialised see function | -| "i_APCI1710_InitChrono" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned char b_ModulNbr, b_OutputChannel, b_InputChannel, b_IOType; - unsigned int dw_Status; - unsigned char *pb_ChannelStatus; - unsigned char *pb_PortValue; - - b_ModulNbr = CR_AREF(insn->chanspec); - i_ReturnValue = insn->n; - b_IOType = (unsigned char) data[0]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - /***********************************/ - /* Test if chronometer initialised */ - /***********************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_ChronoModuleInfo.b_ChronoInit == 1) { - /***********************************/ - /* Test the digital output channel */ - /***********************************/ - switch (b_IOType) { - - case APCI1710_CHRONO_SET_CHANNELOFF: - - b_OutputChannel = - (unsigned char) CR_CHAN(insn->chanspec); - if (b_OutputChannel <= 2) { - - outl(0, devpriv->s_BoardInfos. - ui_Address + 20 + - (b_OutputChannel * 4) + - (64 * b_ModulNbr)); - } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ - else { - /****************************************/ - /* The selected digital output is wrong */ - /****************************************/ - - DPRINTK("The selected digital output is wrong\n"); - i_ReturnValue = -4; - - } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ - - break; - - case APCI1710_CHRONO_SET_CHANNELON: - - b_OutputChannel = - (unsigned char) CR_CHAN(insn->chanspec); - if (b_OutputChannel <= 2) { - - outl(1, devpriv->s_BoardInfos. - ui_Address + 20 + - (b_OutputChannel * 4) + - (64 * b_ModulNbr)); - } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ - else { - /****************************************/ - /* The selected digital output is wrong */ - /****************************************/ - - DPRINTK("The selected digital output is wrong\n"); - i_ReturnValue = -4; - - } /* if ((b_OutputChannel >= 0) && (b_OutputChannel <= 2)) */ - - break; - - case APCI1710_CHRONO_READ_CHANNEL: - /**********************************/ - /* Test the digital input channel */ - /**********************************/ - pb_ChannelStatus = (unsigned char *) &data[0]; - b_InputChannel = - (unsigned char) CR_CHAN(insn->chanspec); - - if (b_InputChannel <= 2) { - - dw_Status = - inl(devpriv-> - s_BoardInfos. - ui_Address + 12 + - (64 * b_ModulNbr)); - - *pb_ChannelStatus = - (unsigned char) (((dw_Status >> - b_InputChannel) - & 1) ^ 1); - } /* if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */ - else { - /***************************************/ - /* The selected digital input is wrong */ - /***************************************/ - - DPRINTK("The selected digital input is wrong\n"); - i_ReturnValue = -4; - } /* if ((b_InputChannel >= 0) && (b_InputChannel <= 2)) */ - - break; - - case APCI1710_CHRONO_READ_PORT: - - pb_PortValue = (unsigned char *) &data[0]; - - dw_Status = - inl(devpriv->s_BoardInfos. - ui_Address + 12 + - (64 * b_ModulNbr)); - - *pb_PortValue = - (unsigned char) ((dw_Status & 0x7) ^ 7); - break; - } - } else { - /*******************************/ - /* Chronometer not initialised */ - /*******************************/ - - DPRINTK("Chronometer not initialised\n"); - i_ReturnValue = -5; - } - } else { - /******************************************/ - /* The module is not a Chronometer module */ - /******************************************/ - - DPRINTK("The module is not a Chronometer module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h deleted file mode 100644 index 29bad1d144a..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Chrono.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_SINGLE 0 -#define APCI1710_CONTINUOUS 1 - -#define APCI1710_CHRONO_PROGRESS_STATUS 0 -#define APCI1710_CHRONO_READVALUE 1 -#define APCI1710_CHRONO_CONVERTVALUE 2 -#define APCI1710_CHRONO_READINTERRUPT 3 - -#define APCI1710_CHRONO_SET_CHANNELON 0 -#define APCI1710_CHRONO_SET_CHANNELOFF 1 -#define APCI1710_CHRONO_READ_CHANNEL 2 -#define APCI1710_CHRONO_READ_PORT 3 - -/* - * CHRONOMETER INISIALISATION FUNCTION - */ -int i_APCI1710_InsnConfigInitChrono(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnWriteEnableDisableChrono(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -/* - * CHRONOMETER READ FUNCTION - */ -int i_APCI1710_InsnReadChrono(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_GetChronoProgressStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_ChronoStatus); - -int i_APCI1710_ReadChronoValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int ui_TimeOut, unsigned char *pb_ChronoStatus, - unsigned int *pul_ChronoValue); - -int i_APCI1710_ConvertChronoValue(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned int ul_ChronoValue, - unsigned int *pul_Hour, - unsigned char *pb_Minute, - unsigned char *pb_Second, - unsigned int *pui_MilliSecond, unsigned int *pui_MicroSecond, - unsigned int *pui_NanoSecond); - -/* - * CHRONOMETER DIGITAL INPUT OUTPUT FUNCTION - */ -int i_APCI1710_InsnBitsChronoDigitalIO(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c deleted file mode 100644 index 07108f9f4a4..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.c +++ /dev/null @@ -1,1025 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : DIG_IO.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 digital I/O module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 16/06/98 | S. Weber | Digital input / output implementation | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ - | | | | - | | | | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ -#include "APCI1710_Dig_io.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, | -| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| -+----------------------------------------------------------------------------+ -| Task : Configure the digital I/O operating mode from selected | -| module (b_ModulNbr). You must calling this function be| -| for you call any other function witch access of digital| -| I/O. | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| unsigned char_ b_ModulNbr data[0]: Module number to | -| configure (0 to 3) | -| unsigned char_ b_ChannelAMode data[1] : Channel A mode selection | -| 0 : Channel used for digital | -| input | -| 1 : Channel used for digital | -| output | -| unsigned char_ b_ChannelBMode data[2] : Channel B mode selection | -| 0 : Channel used for digital | -| input | -| 1 : Channel used for digital | -| output | - data[0] memory on/off -Activates and deactivates the digital output memory. - After having | -| called up this function with memory on,the output you have previously| -| activated with the function are not reset -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: Bi-directional channel A configuration error | -| -5: Bi-directional channel B configuration error | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned char b_ModulNbr, b_ChannelAMode, b_ChannelBMode; - unsigned char b_MemoryOnOff, b_ConfigType; - int i_ReturnValue = 0; - unsigned int dw_WriteConfig = 0; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_ConfigType = (unsigned char) data[0]; /* Memory or Init */ - b_ChannelAMode = (unsigned char) data[1]; - b_ChannelBMode = (unsigned char) data[2]; - b_MemoryOnOff = (unsigned char) data[1]; /* if memory operation */ - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr >= 4) { - DPRINTK("Module Number invalid\n"); - i_ReturnValue = -2; - return i_ReturnValue; - } - switch (b_ConfigType) { - case APCI1710_DIGIO_MEMORYONOFF: - - if (b_MemoryOnOff) /* If Memory ON */ - { - /****************************/ - /* Set the output memory on */ - /****************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_OutputMemoryEnabled = 1; - - /***************************/ - /* Clear the output memory */ - /***************************/ - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.dw_OutputMemory = 0; - } else /* If memory off */ - { - /*****************************/ - /* Set the output memory off */ - /*****************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_OutputMemoryEnabled = 0; - } - break; - - case APCI1710_DIGIO_INIT: - - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - - /***************************************************/ - /* Test the bi-directional channel A configuration */ - /***************************************************/ - - if ((b_ChannelAMode == 0) || (b_ChannelAMode == 1)) { - /***************************************************/ - /* Test the bi-directional channel B configuration */ - /***************************************************/ - - if ((b_ChannelBMode == 0) - || (b_ChannelBMode == 1)) { - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit = - 1; - - /********************************/ - /* Save channel A configuration */ - /********************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelAMode = b_ChannelAMode; - - /********************************/ - /* Save channel B configuration */ - /********************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelBMode = b_ChannelBMode; - - /*****************************************/ - /* Set the channel A and B configuration */ - /*****************************************/ - - dw_WriteConfig = - (unsigned int) (b_ChannelAMode | - (b_ChannelBMode * 2)); - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(dw_WriteConfig, - devpriv->s_BoardInfos. - ui_Address + 4 + - (64 * b_ModulNbr)); - - } else { - /************************************************/ - /* Bi-directional channel B configuration error */ - /************************************************/ - DPRINTK("Bi-directional channel B configuration error\n"); - i_ReturnValue = -5; - } - - } else { - /************************************************/ - /* Bi-directional channel A configuration error */ - /************************************************/ - DPRINTK("Bi-directional channel A configuration error\n"); - i_ReturnValue = -4; - - } - - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - DPRINTK("The module is not a digital I/O module\n"); - i_ReturnValue = -3; - } - } /* end of Switch */ - printk("Return Value %d\n", i_ReturnValue); - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ - -|INT i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev,comedi_subdevice -*s, struct comedi_insn *insn,unsigned int *data) - -+----------------------------------------------------------------------------+ -| Task : Read the status from selected digital I/O digital input| -| (b_InputChannel) | -+----------------------------------------------------------------------------| - - -| -| unsigned char_ b_ModulNbr CR_AREF(chanspec) : Selected module number | -| (0 to 3) | -| unsigned char_ b_InputChannel CR_CHAN(chanspec) : Selection from digital | -| input ( 0 to 6) | -| 0 : Channel C | -| 1 : Channel D | -| 2 : Channel E | -| 3 : Channel F | -| 4 : Channel G | -| 5 : Channel A | -| 6 : Channel B - - - | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : Digital input channel | -| status | -| 0 : Channle is not active| -| 1 : Channle is active | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: The selected digital I/O digital input is wrong | -| -5: Digital I/O not initialised | -| -6: The digital channel A is used for output | -| -7: The digital channel B is used for output | -+----------------------------------------------------------------------------+ -*/ - -/* _INT_ i_APCI1710_ReadDigitalIOChlValue (unsigned char_ b_BoardHandle, */ -/* -* unsigned char_ b_ModulNbr, unsigned char_ b_InputChannel, -* unsigned char *_ pb_ChannelStatus) -*/ -int i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr, b_InputChannel; - unsigned char *pb_ChannelStatus; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec); - data[0] = 0; - pb_ChannelStatus = (unsigned char *) &data[0]; - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /******************************************/ - /* Test the digital imnput channel number */ - /******************************************/ - - if (b_InputChannel <= 6) { - /**********************************************/ - /* Test if the digital I/O module initialised */ - /**********************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit == 1) { - /**********************************/ - /* Test if channel A or channel B */ - /**********************************/ - - if (b_InputChannel > 4) { - /*********************/ - /* Test if channel A */ - /*********************/ - - if (b_InputChannel == 5) { - /***************************/ - /* Test the channel A mode */ - /***************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelAMode - != 0) { - /********************************************/ - /* The digital channel A is used for output */ - /********************************************/ - - i_ReturnValue = - -6; - } - } /* if (b_InputChannel == 5) */ - else { - /***************************/ - /* Test the channel B mode */ - /***************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelBMode - != 0) { - /********************************************/ - /* The digital channel B is used for output */ - /********************************************/ - - i_ReturnValue = - -7; - } - } /* if (b_InputChannel == 5) */ - } /* if (b_InputChannel > 4) */ - - /***********************/ - /* Test if error occur */ - /***********************/ - - if (i_ReturnValue >= 0) { - /**************************/ - /* Read all digital input */ - /**************************/ - -/* -* INPDW (ps_APCI1710Variable-> s_Board [b_BoardHandle]. -* s_BoardInfos. ui_Address + (64 * b_ModulNbr), &dw_StatusReg); -*/ - - dw_StatusReg = - inl(devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - - *pb_ChannelStatus = - (unsigned char) ((dw_StatusReg ^ - 0x1C) >> - b_InputChannel) & 1; - - } /* if (i_ReturnValue == 0) */ - } else { - /*******************************/ - /* Digital I/O not initialised */ - /*******************************/ - DPRINTK("Digital I/O not initialised\n"); - i_ReturnValue = -5; - } - } else { - /********************************/ - /* Selected digital input error */ - /********************************/ - DPRINTK("Selected digital input error\n"); - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - DPRINTK("The module is not a digital I/O module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1710_InsnWriteDigitalIOChlOnOff(comedi_device -|*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) - -+----------------------------------------------------------------------------+ -| Task : Sets or resets the output witch has been passed with the | -| parameter b_Channel. Setting an output means setting | -| an ouput high. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr (aref ) : Selected module number (0 to 3)| -| unsigned char_ b_OutputChannel (CR_CHAN) : Selection from digital output | -| channel (0 to 2) | -| 0 : Channel H | -| 1 : Channel A | -| 2 : Channel B | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: The selected digital output is wrong | -| -5: digital I/O not initialised see function | -| " i_APCI1710_InitDigitalIO" | -| -6: The digital channel A is used for input | -| -7: The digital channel B is used for input - -8: Digital Output Memory OFF. | -| Use previously the function | -| "i_APCI1710_SetDigitalIOMemoryOn". | -+----------------------------------------------------------------------------+ -*/ - -/* -* _INT_ i_APCI1710_SetDigitalIOChlOn (unsigned char_ b_BoardHandle, -* unsigned char_ b_ModulNbr, unsigned char_ b_OutputChannel) -*/ -int i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_WriteValue = 0; - unsigned char b_ModulNbr, b_OutputChannel; - i_ReturnValue = insn->n; - b_ModulNbr = CR_AREF(insn->chanspec); - b_OutputChannel = CR_CHAN(insn->chanspec); - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /**********************************************/ - /* Test if the digital I/O module initialised */ - /**********************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit == 1) { - /******************************************/ - /* Test the digital output channel number */ - /******************************************/ - - switch (b_OutputChannel) { - /*************/ - /* Channel H */ - /*************/ - - case 0: - break; - - /*************/ - /* Channel A */ - /*************/ - - case 1: - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelAMode != 1) { - /*******************************************/ - /* The digital channel A is used for input */ - /*******************************************/ - - i_ReturnValue = -6; - } - break; - - /*************/ - /* Channel B */ - /*************/ - - case 2: - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelBMode != 1) { - /*******************************************/ - /* The digital channel B is used for input */ - /*******************************************/ - - i_ReturnValue = -7; - } - break; - - default: - /****************************************/ - /* The selected digital output is wrong */ - /****************************************/ - - i_ReturnValue = -4; - break; - } - - /***********************/ - /* Test if error occur */ - /***********************/ - - if (i_ReturnValue >= 0) { - - /*********************************/ - /* Test if set channel ON */ - /*********************************/ - if (data[0]) { - /*********************************/ - /* Test if output memory enabled */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_OutputMemoryEnabled == - 1) { - dw_WriteValue = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - | (1 << - b_OutputChannel); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - = dw_WriteValue; - } else { - dw_WriteValue = - 1 << - b_OutputChannel; - } - } /* set channel off */ - else { - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_OutputMemoryEnabled == - 1) { - dw_WriteValue = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - & (0xFFFFFFFFUL - - - (1 << b_OutputChannel)); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - = dw_WriteValue; - } else { - /*****************************/ - /* Digital Output Memory OFF */ - /*****************************/ - /* +Use previously the function "i_APCI1710_SetDigitalIOMemoryOn" */ - i_ReturnValue = -8; - } - - } - /*******************/ - /* Write the value */ - /*******************/ - - /* OUTPDW (ps_APCI1710Variable-> - * s_Board [b_BoardHandle]. - * s_BoardInfos. ui_Address + (64 * b_ModulNbr), - * dw_WriteValue); - */ -*/ - outl(dw_WriteValue, - devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - } - } else { - /*******************************/ - /* Digital I/O not initialised */ - /*******************************/ - - i_ReturnValue = -5; - } - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ - -|INT i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev,comedi_subdevice - *s, struct comedi_insn *insn,unsigned int *data) -+----------------------------------------------------------------------------+ -| Task : write: - Sets or resets one or several outputs from port. | -| Setting an output means setting an output high. | -| If you have switched OFF the digital output memory | -| (OFF), all the other output are set to "0". - -| read: - Read the status from digital input port | -| from selected digital I/O module (b_ModulNbr) -+----------------------------------------------------------------------------+ -| Input Parameters : - unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr CR_AREF(aref) : Selected module number (0 to 3)| -| unsigned char_ b_PortValue CR_CHAN(chanspec) : Output Value ( 0 To 7 ) -| data[0] read or write port -| data[1] if write then indicate ON or OFF - -| if read : data[1] will return port status. -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : - -| INPUT : - - 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: Digital I/O not initialised - - OUTPUT: 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a digital I/O module | -| -4: Output value wrong | -| -5: digital I/O not initialised see function | -| " i_APCI1710_InitDigitalIO" | -| -6: The digital channel A is used for input | -| -7: The digital channel B is used for input - -8: Digital Output Memory OFF. | -| Use previously the function | -| "i_APCI1710_SetDigitalIOMemoryOn". | -+----------------------------------------------------------------------------+ -*/ - -/* - * _INT_ i_APCI1710_SetDigitalIOPortOn (unsigned char_ - * b_BoardHandle, unsigned char_ b_ModulNbr, unsigned char_ - * b_PortValue) -*/ -int i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_WriteValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr, b_PortValue; - unsigned char b_PortOperation, b_PortOnOFF; - - unsigned char *pb_PortValue; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_PortOperation = (unsigned char) data[0]; /* Input or output */ - b_PortOnOFF = (unsigned char) data[1]; /* if output then On or Off */ - b_PortValue = (unsigned char) data[2]; /* if out put then Value */ - i_ReturnValue = insn->n; - pb_PortValue = (unsigned char *) &data[0]; -/* if input then read value */ - - switch (b_PortOperation) { - case APCI1710_INPUT: - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /**********************************************/ - /* Test if the digital I/O module initialised */ - /**********************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit == 1) { - /**************************/ - /* Read all digital input */ - /**************************/ - - /* INPDW (ps_APCI1710Variable-> - * s_Board [b_BoardHandle]. - * s_BoardInfos. - * ui_Address + (64 * b_ModulNbr), - * &dw_StatusReg); - */ - - dw_StatusReg = - inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - *pb_PortValue = - (unsigned char) (dw_StatusReg ^ 0x1C); - - } else { - /*******************************/ - /* Digital I/O not initialised */ - /*******************************/ - - i_ReturnValue = -4; - } - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - i_ReturnValue = -2; - } - - break; - - case APCI1710_OUTPUT: - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if digital I/O counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_DIGITAL_IO) { - /**********************************************/ - /* Test if the digital I/O module initialised */ - /**********************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_DigitalIOInfo.b_DigitalInit == 1) { - /***********************/ - /* Test the port value */ - /***********************/ - - if (b_PortValue <= 7) { - /***********************************/ - /* Test the digital output channel */ - /***********************************/ - - /**************************/ - /* Test if channel A used */ - /**************************/ - - if ((b_PortValue & 2) == 2) { - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelAMode - != 1) { - /*******************************************/ - /* The digital channel A is used for input */ - /*******************************************/ - - i_ReturnValue = - -6; - } - } /* if ((b_PortValue & 2) == 2) */ - - /**************************/ - /* Test if channel B used */ - /**************************/ - - if ((b_PortValue & 4) == 4) { - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_ChannelBMode - != 1) { - /*******************************************/ - /* The digital channel B is used for input */ - /*******************************************/ - - i_ReturnValue = - -7; - } - } /* if ((b_PortValue & 4) == 4) */ - - /***********************/ - /* Test if error occur */ - /***********************/ - - if (i_ReturnValue >= 0) { - - /* if(data[1]) { */ - - switch (b_PortOnOFF) { - /*********************************/ - /* Test if set Port ON */ - /*********************************/ - - case APCI1710_ON: - - /*********************************/ - /* Test if output memory enabled */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_OutputMemoryEnabled - == 1) { - dw_WriteValue - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - | - b_PortValue; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - = - dw_WriteValue; - } else { - dw_WriteValue - = - b_PortValue; - } - break; - - /* If Set PORT OFF */ - case APCI1710_OFF: - - /*********************************/ - /* Test if output memory enabled */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - b_OutputMemoryEnabled - == 1) { - dw_WriteValue - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - & - (0xFFFFFFFFUL - - - b_PortValue); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_DigitalIOInfo. - dw_OutputMemory - = - dw_WriteValue; - } else { - /*****************************/ - /* Digital Output Memory OFF */ - /*****************************/ - - i_ReturnValue - = - -8; - } - } /* switch */ - - /*******************/ - /* Write the value */ - /*******************/ - - /* OUTPDW (ps_APCI1710Variable-> - * s_Board [b_BoardHandle]. - * s_BoardInfos. - * ui_Address + (64 * b_ModulNbr), - * dw_WriteValue); */ - - outl(dw_WriteValue, - devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - } - } else { - /**********************/ - /* Output value wrong */ - /**********************/ - - i_ReturnValue = -4; - } - } else { - /*******************************/ - /* Digital I/O not initialised */ - /*******************************/ - - i_ReturnValue = -5; - } - } else { - /******************************************/ - /* The module is not a digital I/O module */ - /******************************************/ - - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - i_ReturnValue = -2; - } - break; - - default: - i_ReturnValue = -9; - DPRINTK("NO INPUT/OUTPUT specified\n"); - } /* switch INPUT / OUTPUT */ - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h deleted file mode 100644 index cc3973d7c2a..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Dig_io.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_ON 1 /* Digital Output ON or OFF */ -#define APCI1710_OFF 0 - -#define APCI1710_INPUT 0 /* Digital I/O */ -#define APCI1710_OUTPUT 1 - -#define APCI1710_DIGIO_MEMORYONOFF 0x10 -#define APCI1710_DIGIO_INIT 0x11 - -/* - * DIGITAL I/O INISIALISATION FUNCTION - */ -int i_APCI1710_InsnConfigDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * INPUT OUTPUT FUNCTIONS - */ -int i_APCI1710_InsnReadDigitalIOChlValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnWriteDigitalIOChlOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnBitsDigitalIOPortOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c deleted file mode 100644 index 14b13eae4c5..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.c +++ /dev/null @@ -1,5363 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : INC_CPT.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 incremental counter module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ - | 29/06/01 | Guinot C. | - 1100/0231 -> 0701/0232 | - | | | See i_APCI1710_DisableFrequencyMeasurement | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ - -#include "APCI1710_INCCPT.h" - -/* -+----------------------------------------------------------------------------+ -| int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) - -+----------------------------------------------------------------------------+ -| Task : Configuration function for INC_CPT | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : *data -+----------------------------------------------------------------------------+ -| Return Value : | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_ConfigType; - int i_ReturnValue = 0; - ui_ConfigType = CR_CHAN(insn->chanspec); - - printk("\nINC_CPT"); - - devpriv->tsk_Current = current; /* Save the current process task structure */ - switch (ui_ConfigType) { - case APCI1710_INCCPT_INITCOUNTER: - i_ReturnValue = i_APCI1710_InitCounter(dev, - CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], - (unsigned char) data[2], (unsigned char) data[3], (unsigned char) data[4]); - break; - - case APCI1710_INCCPT_COUNTERAUTOTEST: - i_ReturnValue = i_APCI1710_CounterAutoTest(dev, - (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_INITINDEX: - i_ReturnValue = i_APCI1710_InitIndex(dev, - CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], (unsigned char) data[2], (unsigned char) data[3]); - break; - - case APCI1710_INCCPT_INITREFERENCE: - i_ReturnValue = i_APCI1710_InitReference(dev, - CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_INCCPT_INITEXTERNALSTROBE: - i_ReturnValue = i_APCI1710_InitExternalStrobe(dev, - CR_AREF(insn->chanspec), - (unsigned char) data[0], (unsigned char) data[1]); - break; - - case APCI1710_INCCPT_INITCOMPARELOGIC: - i_ReturnValue = i_APCI1710_InitCompareLogic(dev, - CR_AREF(insn->chanspec), (unsigned int) data[0]); - break; - - case APCI1710_INCCPT_INITFREQUENCYMEASUREMENT: - i_ReturnValue = i_APCI1710_InitFrequencyMeasurement(dev, - CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], (unsigned int) data[2], (unsigned int *) &data[0]); - break; - - default: - printk("Insn Config : Config Parameter Wrong\n"); - - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitCounter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_CounterRange, | -| unsigned char_ b_FirstCounterModus, | -| unsigned char_ b_FirstCounterOption, | -| unsigned char_ b_SecondCounterModus, | -| unsigned char_ b_SecondCounterOption) | -+----------------------------------------------------------------------------+ -| Task : Configure the counter operating mode from selected | -| module (b_ModulNbr). You must calling this function be | -| for you call any other function witch access of | -| counters. | -| | -| Counter range | -| ------------- | -| +------------------------------------+-----------------------------------+ | -| | Parameter Passed value | Description | | -| |------------------------------------+-----------------------------------| | -| |b_ModulNbr APCI1710_16BIT_COUNTER | The module is configured for | | -| | | two 16-bit counter. | | -| | | - b_FirstCounterModus and | | -| | | b_FirstCounterOption | | -| | | configure the first 16 bit | | -| | | counter. | | -| | | - b_SecondCounterModus and | | -| | | b_SecondCounterOption | | -| | | configure the second 16 bit | | -| | | counter. | | -| |------------------------------------+-----------------------------------| | -| |b_ModulNbr APCI1710_32BIT_COUNTER | The module is configured for one | | -| | | 32-bit counter. | | -| | | - b_FirstCounterModus and | | -| | | b_FirstCounterOption | | -| | | configure the 32 bit counter. | | -| | | - b_SecondCounterModus and | | -| | | b_SecondCounterOption | | -| | | are not used and have no | | -| | | importance. | | -| +------------------------------------+-----------------------------------+ | -| | -| Counter operating mode | -| ---------------------- | -| | -| +--------------------+-------------------------+-------------------------+ | -| | Parameter | Passed value | Description | | -| |--------------------+-------------------------+-------------------------| | -| |b_FirstCounterModus | APCI1710_QUADRUPLE_MODE | In the quadruple mode, | | -| | or | | the edge analysis | | -| |b_SecondCounterModus| | circuit generates a | | -| | | | counting pulse from | | -| | | | each edge of 2 signals | | -| | | | which are phase shifted | | -| | | | in relation to each | | -| | | | other. | | -| |--------------------+-------------------------+-------------------------| | -| |b_FirstCounterModus | APCI1710_DOUBLE_MODE | Functions in the same | | -| | or | | way as the quadruple | | -| |b_SecondCounterModus| | mode, except that only | | -| | | | two of the four edges | | -| | | | are analysed per | | -| | | | period | | -| |--------------------+-------------------------+-------------------------| | -| |b_FirstCounterModus | APCI1710_SIMPLE_MODE | Functions in the same | | -| | or | | way as the quadruple | | -| |b_SecondCounterModus| | mode, except that only | | -| | | | one of the four edges | | -| | | | is analysed per | | -| | | | period. | | -| |--------------------+-------------------------+-------------------------| | -| |b_FirstCounterModus | APCI1710_DIRECT_MODE | In the direct mode the | | -| | or | | both edge analysis | | -| |b_SecondCounterModus| | circuits are inactive. | | -| | | | The inputs A, B in the | | -| | | | 32-bit mode or A, B and | | -| | | | C, D in the 16-bit mode | | -| | | | represent, each, one | | -| | | | clock pulse gate circuit| | -| | | | There by frequency and | | -| | | | pulse duration | | -| | | | measurements can be | | -| | | | performed. | | -| +--------------------+-------------------------+-------------------------+ | -| | -| | -| IMPORTANT! | -| If you have configured the module for two 16-bit counter, a mixed | -| mode with a counter in quadruple/double/single mode | -| and the other counter in direct mode is not possible! | -| | -| | -| Counter operating option for quadruple/double/simple mode | -| --------------------------------------------------------- | -| | -| +----------------------+-------------------------+------------------------+| -| | Parameter | Passed value | Description || -| |----------------------+-------------------------+------------------------|| -| |b_FirstCounterOption | APCI1710_HYSTERESIS_ON | In both edge analysis || -| | or | | circuits is available || -| |b_SecondCounterOption | | one hysteresis circuit.|| -| | | | It suppresses each || -| | | | time the first counting|| -| | | | pulse after a change || -| | | | of rotation. || -| |----------------------+-------------------------+------------------------|| -| |b_FirstCounterOption | APCI1710_HYSTERESIS_OFF | The first counting || -| | or | | pulse is not suppress || -| |b_SecondCounterOption | | after a change of || -| | | | rotation. || -| +----------------------+-------------------------+------------------------+| -| | -| | -| IMPORTANT! | -| This option are only avaible if you have selected the direct mode. | -| | -| | -| Counter operating option for direct mode | -| ---------------------------------------- | -| | -| +----------------------+--------------------+----------------------------+ | -| | Parameter | Passed value | Description | | -| |----------------------+--------------------+----------------------------| | -| |b_FirstCounterOption | APCI1710_INCREMENT | The counter increment for | | -| | or | | each counting pulse | | -| |b_SecondCounterOption | | | | -| |----------------------+--------------------+----------------------------| | -| |b_FirstCounterOption | APCI1710_DECREMENT | The counter decrement for | | -| | or | | each counting pulse | | -| |b_SecondCounterOption | | | | -| +----------------------+--------------------+----------------------------+ | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_CounterRange : Selection form counter | -| range. | -| unsigned char_ b_FirstCounterModus : First counter operating | -| mode. | -| unsigned char_ b_FirstCounterOption : First counter option. | -| unsigned char_ b_SecondCounterModus : Second counter operating | -| mode. | -| unsigned char_ b_SecondCounterOption : Second counter option. | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module is not a counter module | -| -3: The selected counter range is wrong. | -| -4: The selected first counter operating mode is wrong. | -| -5: The selected first counter operating option is wrong| -| -6: The selected second counter operating mode is wrong.| -| -7: The selected second counter operating option is | -| wrong. | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InitCounter(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_CounterRange, - unsigned char b_FirstCounterModus, - unsigned char b_FirstCounterOption, - unsigned char b_SecondCounterModus, unsigned char b_SecondCounterOption) -{ - int i_ReturnValue = 0; - - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - /**************************/ - /* Test the counter range */ - /**************************/ - - if (b_CounterRange == APCI1710_16BIT_COUNTER - || b_CounterRange == APCI1710_32BIT_COUNTER) { - /********************************/ - /* Test the first counter modus */ - /********************************/ - - if (b_FirstCounterModus == APCI1710_QUADRUPLE_MODE || - b_FirstCounterModus == APCI1710_DOUBLE_MODE || - b_FirstCounterModus == APCI1710_SIMPLE_MODE || - b_FirstCounterModus == APCI1710_DIRECT_MODE) { - /*********************************/ - /* Test the first counter option */ - /*********************************/ - - if ((b_FirstCounterModus == APCI1710_DIRECT_MODE - && (b_FirstCounterOption == - APCI1710_INCREMENT - || b_FirstCounterOption - == APCI1710_DECREMENT)) - || (b_FirstCounterModus != - APCI1710_DIRECT_MODE - && (b_FirstCounterOption == - APCI1710_HYSTERESIS_ON - || b_FirstCounterOption - == - APCI1710_HYSTERESIS_OFF))) - { - /**************************/ - /* Test if 16-bit counter */ - /**************************/ - - if (b_CounterRange == - APCI1710_16BIT_COUNTER) { - /*********************************/ - /* Test the second counter modus */ - /*********************************/ - - if ((b_FirstCounterModus != - APCI1710_DIRECT_MODE - && - (b_SecondCounterModus - == - APCI1710_QUADRUPLE_MODE - || - b_SecondCounterModus - == - APCI1710_DOUBLE_MODE - || - b_SecondCounterModus - == - APCI1710_SIMPLE_MODE)) - || (b_FirstCounterModus - == - APCI1710_DIRECT_MODE - && - b_SecondCounterModus - == - APCI1710_DIRECT_MODE)) - { - /**********************************/ - /* Test the second counter option */ - /**********************************/ - - if ((b_SecondCounterModus == APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_INCREMENT || b_SecondCounterOption == APCI1710_DECREMENT)) || (b_SecondCounterModus != APCI1710_DIRECT_MODE && (b_SecondCounterOption == APCI1710_HYSTERESIS_ON || b_SecondCounterOption == APCI1710_HYSTERESIS_OFF))) { - i_ReturnValue = - 0; - } else { - /*********************************************************/ - /* The selected second counter operating option is wrong */ - /*********************************************************/ - - DPRINTK("The selected second counter operating option is wrong\n"); - i_ReturnValue = - -7; - } - } else { - /*******************************************************/ - /* The selected second counter operating mode is wrong */ - /*******************************************************/ - - DPRINTK("The selected second counter operating mode is wrong\n"); - i_ReturnValue = -6; - } - } - } else { - /********************************************************/ - /* The selected first counter operating option is wrong */ - /********************************************************/ - - DPRINTK("The selected first counter operating option is wrong\n"); - i_ReturnValue = -5; - } - } else { - /******************************************************/ - /* The selected first counter operating mode is wrong */ - /******************************************************/ - DPRINTK("The selected first counter operating mode is wrong\n"); - i_ReturnValue = -4; - } - } else { - /***************************************/ - /* The selected counter range is wrong */ - /***************************************/ - - DPRINTK("The selected counter range is wrong\n"); - i_ReturnValue = -3; - } - - /*************************/ - /* Test if a error occur */ - /*************************/ - - if (i_ReturnValue == 0) { - /**************************/ - /* Test if 16-Bit counter */ - /**************************/ - - if (b_CounterRange == APCI1710_32BIT_COUNTER) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 = b_CounterRange | - b_FirstCounterModus | - b_FirstCounterOption; - } else { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 = b_CounterRange | - (b_FirstCounterModus & 0x5) | - (b_FirstCounterOption & 0x20) | - (b_SecondCounterModus & 0xA) | - (b_SecondCounterOption & 0x40); - - /***********************/ - /* Test if direct mode */ - /***********************/ - - if (b_FirstCounterModus == APCI1710_DIRECT_MODE) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 | - APCI1710_DIRECT_MODE; - } - } - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_CounterInit = 1; - } - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_CounterAutoTest | -| (unsigned char_ b_BoardHandle, | -| unsigned char *_ pb_TestStatus) | -+----------------------------------------------------------------------------+ -| Task : A test mode is intended for testing the component and | -| the connected periphery. All the 8-bit counter chains | -| are operated internally as down counters. | -| Independently from the external signals, | -| all the four 8-bit counter chains are decremented in | -| parallel by each negative clock pulse edge of CLKX. | -| | -| Counter auto test conclusion | -| ---------------------------- | -| +-----------------+-----------------------------+ | -| | pb_TestStatus | Error description | | -| | mask | | | -| |-----------------+-----------------------------| | -| | 0000 | No error detected | | -| |-----------------|-----------------------------| | -| | 0001 | Error detected of counter 0 | | -| |-----------------|-----------------------------| | -| | 0010 | Error detected of counter 1 | | -| |-----------------|-----------------------------| | -| | 0100 | Error detected of counter 2 | | -| |-----------------|-----------------------------| | -| | 1000 | Error detected of counter 3 | | -| +-----------------+-----------------------------+ | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TestStatus : Auto test conclusion. See table| -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_CounterAutoTest(struct comedi_device *dev, unsigned char *pb_TestStatus) -{ - unsigned char b_ModulCpt = 0; - int i_ReturnValue = 0; - unsigned int dw_LathchValue; - - *pb_TestStatus = 0; - - /********************************/ - /* Test if counter module found */ - /********************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[0] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[1] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[2] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[3] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) { - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulCpt] & - 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - /******************/ - /* Start the test */ - /******************/ - - outl(3, devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulCpt)); - - /*********************/ - /* Tatch the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulCpt)); - - /************************/ - /* Read the latch value */ - /************************/ - - dw_LathchValue = inl(devpriv->s_BoardInfos. - ui_Address + 4 + (64 * b_ModulCpt)); - - if ((dw_LathchValue & 0xFF) != - ((dw_LathchValue >> 8) & 0xFF) - && (dw_LathchValue & 0xFF) != - ((dw_LathchValue >> 16) & 0xFF) - && (dw_LathchValue & 0xFF) != - ((dw_LathchValue >> 24) & 0xFF)) { - *pb_TestStatus = - *pb_TestStatus | (1 << - b_ModulCpt); - } - - /*****************/ - /* Stop the test */ - /*****************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulCpt)); - } - } - } else { - /***************************/ - /* No counter module found */ - /***************************/ - - DPRINTK("No counter module found\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitIndex (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_ReferenceAction, | -| unsigned char_ b_IndexOperation, | -| unsigned char_ b_AutoMode, | -| unsigned char_ b_InterruptEnable) | -+----------------------------------------------------------------------------+ -| Task : Initialise the index corresponding to the selected | -| module (b_ModulNbr). If a INDEX flag occur, you have | -| the possibility to clear the 32-Bit counter or to latch| -| the current 32-Bit value in to the first latch | -| register. The b_IndexOperation parameter give the | -| possibility to choice the INDEX action. | -| If you have enabled the automatic mode, each INDEX | -| action is cleared automatically, else you must read | -| the index status ("i_APCI1710_ReadIndexStatus") | -| after each INDEX action. | -| | -| | -| Index action | -| ------------ | -| | -| +------------------------+------------------------------------+ | -| | b_IndexOperation | Operation | | -| |------------------------+------------------------------------| | -| |APCI1710_LATCH_COUNTER | After a index signal, the counter | | -| | | value (32-Bit) is latched in to | | -| | | the first latch register | | -| |------------------------|------------------------------------| | -| |APCI1710_CLEAR_COUNTER | After a index signal, the counter | | -| | | value is cleared (32-Bit) | | -| +------------------------+------------------------------------+ | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_ReferenceAction : Determine if the reference | -| must set or no for the | -| acceptance from index | -| APCI1710_ENABLE : | -| Reference must be set for | -| accepted the index | -| APCI1710_DISABLE : | -| Reference have not | -| importance | -| unsigned char_ b_IndexOperation : Index operating mode. | -| See table. | -| unsigned char_ b_AutoMode : Enable or disable the | -| automatic index reset. | -| APCI1710_ENABLE : | -| Enable the automatic mode | -| APCI1710_DISABLE : | -| Disable the automatic mode | -| unsigned char_ b_InterruptEnable : Enable or disable the | -| interrupt. | -| APCI1710_ENABLE : | -| Enable the interrupt | -| APCI1710_DISABLE : | -| Disable the interrupt | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4 The reference action parameter is wrong | -| -5: The index operating mode parameter is wrong | -| -6: The auto mode parameter is wrong | -| -7: Interrupt parameter is wrong | -| -8: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InitIndex(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_ReferenceAction, - unsigned char b_IndexOperation, unsigned char b_AutoMode, unsigned char b_InterruptEnable) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /********************************/ - /* Test the reference parameter */ - /********************************/ - - if (b_ReferenceAction == APCI1710_ENABLE || - b_ReferenceAction == APCI1710_DISABLE) { - /****************************/ - /* Test the index parameter */ - /****************************/ - - if (b_IndexOperation == - APCI1710_HIGH_EDGE_LATCH_COUNTER - || b_IndexOperation == - APCI1710_LOW_EDGE_LATCH_COUNTER - || b_IndexOperation == - APCI1710_HIGH_EDGE_CLEAR_COUNTER - || b_IndexOperation == - APCI1710_LOW_EDGE_CLEAR_COUNTER - || b_IndexOperation == - APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER - || b_IndexOperation == - APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) - { - /********************************/ - /* Test the auto mode parameter */ - /********************************/ - - if (b_AutoMode == APCI1710_ENABLE || - b_AutoMode == APCI1710_DISABLE) - { - /***************************/ - /* Test the interrupt mode */ - /***************************/ - - if (b_InterruptEnable == - APCI1710_ENABLE - || b_InterruptEnable == - APCI1710_DISABLE) { - - /************************************/ - /* Makte the configuration commando */ - /************************************/ - - if (b_ReferenceAction == - APCI1710_ENABLE) - { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - | - APCI1710_ENABLE_INDEX_ACTION; - } else { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - & - APCI1710_DISABLE_INDEX_ACTION; - } - - /****************************************/ - /* Test if low level latch or/and clear */ - /****************************************/ - - if (b_IndexOperation == - APCI1710_LOW_EDGE_LATCH_COUNTER - || - b_IndexOperation - == - APCI1710_LOW_EDGE_CLEAR_COUNTER - || - b_IndexOperation - == - APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) - { - /*************************************/ - /* Set the index level to low (DQ26) */ - /*************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - | - APCI1710_SET_LOW_INDEX_LEVEL; - } else { - /**************************************/ - /* Set the index level to high (DQ26) */ - /**************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & - APCI1710_SET_HIGH_INDEX_LEVEL; - } - - /***********************************/ - /* Test if latch and clear counter */ - /***********************************/ - - if (b_IndexOperation == - APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER - || - b_IndexOperation - == - APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) - { - /***************************************/ - /* Set the latch and clear flag (DQ27) */ - /***************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - | - APCI1710_ENABLE_LATCH_AND_CLEAR; - } /* if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */ - else { - /*****************************************/ - /* Clear the latch and clear flag (DQ27) */ - /*****************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & - APCI1710_DISABLE_LATCH_AND_CLEAR; - - /*************************/ - /* Test if latch counter */ - /*************************/ - - if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_COUNTER) { - /*********************************/ - /* Enable the latch from counter */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - | - APCI1710_INDEX_LATCH_COUNTER; - } else { - /*********************************/ - /* Enable the clear from counter */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - & - (~APCI1710_INDEX_LATCH_COUNTER); - } - } /* // if (b_IndexOperation == APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER || b_IndexOperation == APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER) */ - - if (b_AutoMode == - APCI1710_DISABLE) - { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - | - APCI1710_INDEX_AUTO_MODE; - } else { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 - & - (~APCI1710_INDEX_AUTO_MODE); - } - - if (b_InterruptEnable == - APCI1710_ENABLE) - { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - | - APCI1710_ENABLE_INDEX_INT; - } else { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - & - APCI1710_DISABLE_INDEX_INT; - } - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_IndexInit = 1; - - } else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue = -7; - } - } else { - /************************************/ - /* The auto mode parameter is wrong */ - /************************************/ - - DPRINTK("The auto mode parameter is wrong\n"); - i_ReturnValue = -6; - } - } else { - /***********************************************/ - /* The index operating mode parameter is wrong */ - /***********************************************/ - - DPRINTK("The index operating mode parameter is wrong\n"); - i_ReturnValue = -5; - } - } else { - /*******************************************/ - /* The reference action parameter is wrong */ - /*******************************************/ - - DPRINTK("The reference action parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitReference | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_ReferenceLevel) | -+----------------------------------------------------------------------------+ -| Task : Initialise the reference corresponding to the selected | -| module (b_ModulNbr). | -| | -| Reference level | -| --------------- | -| +--------------------+-------------------------+ | -| | b_ReferenceLevel | Operation | | -| +--------------------+-------------------------+ | -| | APCI1710_LOW | Reference occur if "0" | | -| |--------------------|-------------------------| | -| | APCI1710_HIGH | Reference occur if "1" | | -| +--------------------+-------------------------+ | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_ReferenceLevel : Reference level. | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number parameter is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Reference level parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InitReference(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_ReferenceLevel) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /**************************************/ - /* Test the reference level parameter */ - /**************************************/ - - if (b_ReferenceLevel == 0 || b_ReferenceLevel == 1) { - if (b_ReferenceLevel == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 | - APCI1710_REFERENCE_HIGH; - } else { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & - APCI1710_REFERENCE_LOW; - } - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_ReferenceInit = 1; - } else { - /**************************************/ - /* Reference level parameter is wrong */ - /**************************************/ - - DPRINTK("Reference level parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitExternalStrobe | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_ExternalStrobe, | -| unsigned char_ b_ExternalStrobeLevel) | -+----------------------------------------------------------------------------+ -| Task : Initialises the external strobe level corresponding to | -| the selected module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_ExternalStrobe : External strobe selection | -| 0 : External strobe A | -| 1 : External strobe B | -| unsigned char_ b_ExternalStrobeLevel : External strobe level | -| APCI1710_LOW : | -| External latch occurs if "0" | -| APCI1710_HIGH : | -| External latch occurs if "1" | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: Counter not initialised. | -| See function "i_APCI1710_InitCounter" | -| -4: External strobe selection is wrong | -| -5: External strobe level parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InitExternalStrobe(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_ExternalStrobe, unsigned char b_ExternalStrobeLevel) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /**************************************/ - /* Test the external strobe selection */ - /**************************************/ - - if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) { - /******************/ - /* Test the level */ - /******************/ - - if ((b_ExternalStrobeLevel == APCI1710_HIGH) || - ((b_ExternalStrobeLevel == APCI1710_LOW - && (devpriv-> - s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) >= - 0x3135))) { - /*****************/ - /* Set the level */ - /*****************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 = (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 & (0xFF - - (0x10 << b_ExternalStrobe))) | ((b_ExternalStrobeLevel ^ 1) << (4 + b_ExternalStrobe)); - } else { - /********************************************/ - /* External strobe level parameter is wrong */ - /********************************************/ - - DPRINTK("External strobe level parameter is wrong\n"); - i_ReturnValue = -5; - } - } /* if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */ - else { - /**************************************/ - /* External strobe selection is wrong */ - /**************************************/ - - DPRINTK("External strobe selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_ExternalStrobe == 0 || b_ExternalStrobe == 1) */ - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_InitCompareLogic | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr, | - | unsigned int_ ui_CompareValue) | - +----------------------------------------------------------------------------+ - | Task : Set the 32-Bit compare value. At that moment that the | - | incremental counter arrive to the compare value | - | (ui_CompareValue) a interrupt is generated. | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | - | unsigned char_ b_ModulNbr : Module number to configure | - | (0 to 3) | - | unsigned int_ ui_CompareValue : 32-Bit compare value | - +----------------------------------------------------------------------------+ - | Output Parameters : - - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: No counter module found | - | -3: Counter not initialised see function | - | "i_APCI1710_InitCounter" | - +----------------------------------------------------------------------------+ - */ - -int i_APCI1710_InitCompareLogic(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned int ui_CompareValue) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - - outl(ui_CompareValue, devpriv->s_BoardInfos. - ui_Address + 28 + (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_CompareLogicInit = 1; - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitFrequencyMeasurement | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PCIInputClock, | -| unsigned char_ b_TimingUnity, | -| ULONG_ ul_TimingInterval, | -| PULONG_ pul_RealTimingInterval) | -+----------------------------------------------------------------------------+ -| Task : Sets the time for the frequency measurement. | -| Configures the selected TOR incremental counter of the | -| selected module (b_ModulNbr). The ul_TimingInterval and| -| ul_TimingUnity determine the time base for the | -| measurement. The pul_RealTimingInterval returns the | -| real time value. You must call up this function before | -| you call up any other function which gives access to | -| the frequency measurement. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Number of the module to be | -| configured (0 to 3) | -| unsigned char_ b_PCIInputClock : Selection of the PCI bus | -| clock | -| - APCI1710_30MHZ : | -| The PC has a PCI bus clock | -| of 30 MHz | -| - APCI1710_33MHZ : | -| The PC has a PCI bus clock | -| of 33 MHz | -| unsigned char_ b_TimingUnity : Base time unit (0 to 2) | -| 0 : ns | -| 1 : æs | -| 2 : ms | -| ULONG_ ul_TimingInterval: Base time value. | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_RealTimingInterval : Real base time value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected PCI input clock is wrong | -| -5: Timing unity selection is wrong | -| -6: Base timing selection is wrong | -| -7: 40MHz quartz not on board | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PCIInputClock, - unsigned char b_TimingUnity, - unsigned int ul_TimingInterval, unsigned int *pul_RealTimingInterval) -{ - int i_ReturnValue = 0; - unsigned int ul_TimerValue = 0; - double d_RealTimingInterval; - unsigned int dw_Status = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /**************************/ - /* Test the PCI bus clock */ - /**************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ) || - (b_PCIInputClock == APCI1710_33MHZ) || - (b_PCIInputClock == APCI1710_40MHZ)) { - /************************/ - /* Test the timing unit */ - /************************/ - - if (b_TimingUnity <= 2) { - /**********************************/ - /* Test the base timing selection */ - /**********************************/ - - if (((b_PCIInputClock == APCI1710_30MHZ) - && (b_TimingUnity == 0) - && (ul_TimingInterval >= - 266) - && (ul_TimingInterval <= - 8738133UL)) - || ((b_PCIInputClock == - APCI1710_30MHZ) - && (b_TimingUnity == 1) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 8738UL)) - || ((b_PCIInputClock == - APCI1710_30MHZ) - && (b_TimingUnity == 2) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 8UL)) - || ((b_PCIInputClock == - APCI1710_33MHZ) - && (b_TimingUnity == 0) - && (ul_TimingInterval >= - 242) - && (ul_TimingInterval <= - 7943757UL)) - || ((b_PCIInputClock == - APCI1710_33MHZ) - && (b_TimingUnity == 1) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 7943UL)) - || ((b_PCIInputClock == - APCI1710_33MHZ) - && (b_TimingUnity == 2) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 7UL)) - || ((b_PCIInputClock == - APCI1710_40MHZ) - && (b_TimingUnity == 0) - && (ul_TimingInterval >= - 200) - && (ul_TimingInterval <= - 6553500UL)) - || ((b_PCIInputClock == - APCI1710_40MHZ) - && (b_TimingUnity == 1) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 6553UL)) - || ((b_PCIInputClock == - APCI1710_40MHZ) - && (b_TimingUnity == 2) - && (ul_TimingInterval >= - 1) - && (ul_TimingInterval <= - 6UL))) { - /**********************/ - /* Test if 40MHz used */ - /**********************/ - - if (b_PCIInputClock == - APCI1710_40MHZ) { - /******************************/ - /* Test if firmware >= Rev1.5 */ - /******************************/ - - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3135) { - /*********************************/ - /* Test if 40MHz quartz on board */ - /*********************************/ - - /*INPDW (ps_APCI1710Variable-> - s_Board [b_BoardHandle]. - s_BoardInfos. - ui_Address + 36 + (64 * b_ModulNbr), &dw_Status); */ - dw_Status = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + 36 + - (64 * b_ModulNbr)); - - /******************************/ - /* Test the quartz flag (DQ0) */ - /******************************/ - - if ((dw_Status & 1) != 1) { - /*****************************/ - /* 40MHz quartz not on board */ - /*****************************/ - - DPRINTK("40MHz quartz not on board\n"); - i_ReturnValue - = - -7; - } - } else { - /*****************************/ - /* 40MHz quartz not on board */ - /*****************************/ - DPRINTK("40MHz quartz not on board\n"); - i_ReturnValue = - -7; - } - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - - /***************************/ - /* Test if not error occur */ - /***************************/ - - if (i_ReturnValue == 0) { - /****************************/ - /* Test the INC_CPT version */ - /****************************/ - - if ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131) { - - /**********************/ - /* Test if 40MHz used */ - /**********************/ - - if (b_PCIInputClock == APCI1710_40MHZ) { - /*********************************/ - /* Enable the 40MHz quarz (DQ30) */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - | - APCI1710_ENABLE_40MHZ_FREQUENCY; - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - else { - /**********************************/ - /* Disable the 40MHz quarz (DQ30) */ - /**********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & - APCI1710_DISABLE_40MHZ_FREQUENCY; - - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - - /********************************/ - /* Calculate the division fator */ - /********************************/ - - fpu_begin(); - switch (b_TimingUnity) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.00025 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.00025 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (0.00025 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) { - *pul_RealTimingInterval - = - *pul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.25 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.25 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - ( - (double) - 0.25 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) { - *pul_RealTimingInterval - = - *pul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - ul_TimingInterval - * - (250.0 - * - b_PCIInputClock); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (250.0 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (250.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)*pul_RealTimingInterval + 0.5)) { - *pul_RealTimingInterval - = - *pul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - break; - } - - fpu_end(); - /*************************/ - /* Write the timer value */ - /*************************/ - - outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 32 + (64 * b_ModulNbr)); - - /*******************************/ - /* Set the initialisation flag */ - /*******************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_FrequencyMeasurementInit - = 1; - } else { - /***************************/ - /* Counter not initialised */ - /***************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = - -3; - } - } /* if (i_ReturnValue == 0) */ - } else { - /**********************************/ - /* Base timing selection is wrong */ - /**********************************/ - - DPRINTK("Base timing selection is wrong\n"); - i_ReturnValue = -6; - } - } else { - /***********************************/ - /* Timing unity selection is wrong */ - /***********************************/ - - DPRINTK("Timing unity selection is wrong\n"); - i_ReturnValue = -5; - } - } else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/*########################################################################### */ - - /* INSN BITS */ -/*########################################################################### */ - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Set & Clear Functions for INC_CPT | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_BitsType; - int i_ReturnValue = 0; - ui_BitsType = CR_CHAN(insn->chanspec); - devpriv->tsk_Current = current; /* Save the current process task structure */ - - switch (ui_BitsType) { - case APCI1710_INCCPT_CLEARCOUNTERVALUE: - i_ReturnValue = i_APCI1710_ClearCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_CLEARALLCOUNTERVALUE: - i_ReturnValue = i_APCI1710_ClearAllCounterValue(dev); - break; - - case APCI1710_INCCPT_SETINPUTFILTER: - i_ReturnValue = i_APCI1710_SetInputFilter(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) data[0], (unsigned char) data[1]); - break; - - case APCI1710_INCCPT_LATCHCOUNTER: - i_ReturnValue = i_APCI1710_LatchCounter(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE: - i_ReturnValue = i_APCI1710_SetIndexAndReferenceSource(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_INCCPT_SETDIGITALCHLON: - i_ReturnValue = i_APCI1710_SetDigitalChlOn(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_SETDIGITALCHLOFF: - i_ReturnValue = i_APCI1710_SetDigitalChlOff(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - default: - printk("Bits Config Parameter Wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ClearCounterValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Clear the counter value from selected module | -| (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number parameter is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_ClearCounterValue(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*********************/ - /* Clear the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ClearAllCounterValue | -| (unsigned char_ b_BoardHandle) | -+----------------------------------------------------------------------------+ -| Task : Clear all counter value. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_ClearAllCounterValue(struct comedi_device *dev) -{ - unsigned char b_ModulCpt = 0; - int i_ReturnValue = 0; - - /********************************/ - /* Test if counter module found */ - /********************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[0] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[1] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[2] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER - || (devpriv->s_BoardInfos. - dw_MolduleConfiguration[3] & 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - for (b_ModulCpt = 0; b_ModulCpt < 4; b_ModulCpt++) { - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulCpt] & - 0xFFFF0000UL) == - APCI1710_INCREMENTAL_COUNTER) { - /*********************/ - /* Clear the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulCpt)); - } - } - } else { - /***************************/ - /* No counter module found */ - /***************************/ - - DPRINTK("No counter module found\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetInputFilter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_Module, | -| unsigned char_ b_PCIInputClock, | -| unsigned char_ b_Filter) | -+----------------------------------------------------------------------------+ -| Task : Disable or enable the software filter from selected | -| module (b_ModulNbr). b_Filter determine the filter time| -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Number of the module to be | -| configured (0 to 3) | -| unsigned char_ b_PCIInputClock : Selection of the PCI bus | -| clock | -| - APCI1710_30MHZ : | -| The PC has a PCI bus clock | -| of 30 MHz | -| - APCI1710_33MHZ : | -| The PC has a PCI bus clock | -| of 33 MHz | -| - APCI1710_40MHZ : | -| The APCI1710 has a 40MHz | -| quartz | -| unsigned char_ b_Filter : Filter selection | -| | -| 30 MHz | -| ------ | -| 0: Software filter not used | -| 1: Filter from 266ns (3.750000MHz) | -| 2: Filter from 400ns (2.500000MHz) | -| 3: Filter from 533ns (1.876170MHz) | -| 4: Filter from 666ns (1.501501MHz) | -| 5: Filter from 800ns (1.250000MHz) | -| 6: Filter from 933ns (1.071800MHz) | -| 7: Filter from 1066ns (0.938080MHz) | -| 8: Filter from 1200ns (0.833333MHz) | -| 9: Filter from 1333ns (0.750000MHz) | -| 10: Filter from 1466ns (0.682100MHz) | -| 11: Filter from 1600ns (0.625000MHz) | -| 12: Filter from 1733ns (0.577777MHz) | -| 13: Filter from 1866ns (0.535900MHz) | -| 14: Filter from 2000ns (0.500000MHz) | -| 15: Filter from 2133ns (0.468800MHz) | -| | -| 33 MHz | -| ------ | -| 0: Software filter not used | -| 1: Filter from 242ns (4.125000MHz) | -| 2: Filter from 363ns (2.754820MHz) | -| 3: Filter from 484ns (2.066115MHz) | -| 4: Filter from 605ns (1.652892MHz) | -| 5: Filter from 726ns (1.357741MHz) | -| 6: Filter from 847ns (1.180637MHz) | -| 7: Filter from 968ns (1.033055MHz) | -| 8: Filter from 1089ns (0.918273MHz) | -| 9: Filter from 1210ns (0.826446MHz) | -| 10: Filter from 1331ns (0.751314MHz) | -| 11: Filter from 1452ns (0.688705MHz) | -| 12: Filter from 1573ns (0.635727MHz) | -| 13: Filter from 1694ns (0.590318MHz) | -| 14: Filter from 1815ns (0.550964MHz) | -| 15: Filter from 1936ns (0.516528MHz) | -| | -| 40 MHz | -| ------ | -| 0: Software filter not used | -| 1: Filter from 200ns (5.000000MHz) | -| 2: Filter from 300ns (3.333333MHz) | -| 3: Filter from 400ns (2.500000MHz) | -| 4: Filter from 500ns (2.000000MHz) | -| 5: Filter from 600ns (1.666666MHz) | -| 6: Filter from 700ns (1.428500MHz) | -| 7: Filter from 800ns (1.250000MHz) | -| 8: Filter from 900ns (1.111111MHz) | -| 9: Filter from 1000ns (1.000000MHz) | -| 10: Filter from 1100ns (0.909090MHz) | -| 11: Filter from 1200ns (0.833333MHz) | -| 12: Filter from 1300ns (0.769200MHz) | -| 13: Filter from 1400ns (0.714200MHz) | -| 14: Filter from 1500ns (0.666666MHz) | -| 15: Filter from 1600ns (0.625000MHz) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: The module is not a counter module | -| -4: The selected PCI input clock is wrong | -| -5: The selected filter value is wrong | -| -6: 40MHz quartz not on board | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_SetInputFilter(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_PCIInputClock, unsigned char b_Filter) -{ - int i_ReturnValue = 0; - unsigned int dw_Status = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) { - /******************************/ - /* Test if firmware >= Rev1.5 */ - /******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF) >= 0x3135) { - /**************************/ - /* Test the PCI bus clock */ - /**************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ) || - (b_PCIInputClock == APCI1710_33MHZ) || - (b_PCIInputClock == APCI1710_40MHZ)) { - /*************************/ - /* Test the filter value */ - /*************************/ - - if (b_Filter < 16) { - /**********************/ - /* Test if 40MHz used */ - /**********************/ - - if (b_PCIInputClock == - APCI1710_40MHZ) { - /*********************************/ - /* Test if 40MHz quartz on board */ - /*********************************/ - - dw_Status = - inl(devpriv-> - s_BoardInfos. - ui_Address + - 36 + - (64 * b_ModulNbr)); - - /******************************/ - /* Test the quartz flag (DQ0) */ - /******************************/ - - if ((dw_Status & 1) != - 1) { - /*****************************/ - /* 40MHz quartz not on board */ - /*****************************/ - - DPRINTK("40MHz quartz not on board\n"); - i_ReturnValue = - -6; - } - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - - /***************************/ - /* Test if error not occur */ - /***************************/ - - if (i_ReturnValue == 0) { - /**********************/ - /* Test if 40MHz used */ - /**********************/ - - if (b_PCIInputClock == - APCI1710_40MHZ) - { - /*********************************/ - /* Enable the 40MHz quarz (DQ31) */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - | - APCI1710_ENABLE_40MHZ_FILTER; - - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - else { - /**********************************/ - /* Disable the 40MHz quarz (DQ31) */ - /**********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & - APCI1710_DISABLE_40MHZ_FILTER; - - } /* if (b_PCIInputClock == APCI1710_40MHZ) */ - - /************************/ - /* Set the filter value */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 - & 0x1F) | - ((b_Filter & - 0x7) << - 5); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 - & 0xFE) | - ((b_Filter & - 0x8) >> - 3); - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv-> - s_BoardInfos. - ui_Address + - 20 + - (64 * b_ModulNbr)); - } /* if (i_ReturnValue == 0) */ - } /* if (b_Filter < 16) */ - else { - /**************************************/ - /* The selected filter value is wrong */ - /**************************************/ - - DPRINTK("The selected filter value is wrong\n"); - i_ReturnValue = -5; - } /* if (b_Filter < 16) */ - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */ - else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = 4; - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ) || (b_PCIInputClock == APCI1710_40MHZ)) */ - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -3; - } - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_LatchCounter (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_LatchReg) | -+----------------------------------------------------------------------------+ -| Task : Latch the courant value from selected module | -| (b_ModulNbr) in to the selected latch register | -| (b_LatchReg). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_LatchReg : Selected latch register | -| 0 : for the first latch register | -| 1 : for the second latch register | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected latch register parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_LatchCounter(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_LatchReg) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test the latch register parameter */ - /*************************************/ - - if (b_LatchReg < 2) { - /*********************/ - /* Tatch the counter */ - /*********************/ - - outl(1 << (b_LatchReg * 4), - devpriv->s_BoardInfos.ui_Address + - (64 * b_ModulNbr)); - } else { - /**************************************************/ - /* The selected latch register parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected latch register parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetIndexAndReferenceSource | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SourceSelection) | -+----------------------------------------------------------------------------+ -| Task : Determine the hardware source for the index and the | -| reference logic. Per default the index logic is | -| connected to the difference input C and the reference | -| logic is connected to the 24V input E | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_SourceSelection : APCI1710_SOURCE_0 : | -| The index logic is connected | -| to the difference input C and| -| the reference logic is | -| connected to the 24V input E.| -| This is the default | -| configuration. | -| APCI1710_SOURCE_1 : | -| The reference logic is | -| connected to the difference | -| input C and the index logic | -| is connected to the 24V | -| input E | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: The module is not a counter module. | -| -4: The source selection is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_SourceSelection) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if incremental counter */ - /*******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) { - /******************************/ - /* Test if firmware >= Rev1.5 */ - /******************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF) >= 0x3135) { - /*****************************/ - /* Test the source selection */ - /*****************************/ - - if (b_SourceSelection == APCI1710_SOURCE_0 || - b_SourceSelection == APCI1710_SOURCE_1) - { - /******************************************/ - /* Test if invert the index and reference */ - /******************************************/ - - if (b_SourceSelection == - APCI1710_SOURCE_1) { - /********************************************/ - /* Invert index and reference source (DQ25) */ - /********************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 | - APCI1710_INVERT_INDEX_RFERENCE; - } else { - /****************************************/ - /* Set the default configuration (DQ25) */ - /****************************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister4 & - APCI1710_DEFAULT_INDEX_RFERENCE; - } - } /* if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */ - else { - /*********************************/ - /* The source selection is wrong */ - /*********************************/ - - DPRINTK("The source selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_SourceSelection == APCI1710_SOURCE_0 ||b_SourceSelection == APCI1710_SOURCE_1) */ - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -3; - } - } else { - /**************************************/ - /* The module is not a counter module */ - /**************************************/ - - DPRINTK("The module is not a counter module\n"); - i_ReturnValue = -3; - } - } else { - /***************************************/ - /* The selected module number is wrong */ - /***************************************/ - - DPRINTK("The selected module number is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetDigitalChlOn | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Sets the digital output H Setting an output means | -| setting an ouput high. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Number of the module to be | -| configured (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_SetDigitalChlOn(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister.b_ModeRegister3 | 0x10; - - /*********************/ - /* Set the output On */ - /*********************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetDigitalChlOff | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Resets the digital output H. Resetting an output means | -| setting an ouput low. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Number of the module to be | -| configured (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The selected module number is wrong | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_SetDigitalChlOff(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister.b_ModeRegister3 & 0xEF; - - /**********************/ - /* Set the output Off */ - /**********************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/*########################################################################### */ - - /* INSN WRITE */ -/*########################################################################### */ - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Enable Disable functions for INC_CPT | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ -int i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_WriteType; - int i_ReturnValue = 0; - - ui_WriteType = CR_CHAN(insn->chanspec); - devpriv->tsk_Current = current; /* Save the current process task structure */ - - switch (ui_WriteType) { - case APCI1710_INCCPT_ENABLELATCHINTERRUPT: - i_ReturnValue = i_APCI1710_EnableLatchInterrupt(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_DISABLELATCHINTERRUPT: - i_ReturnValue = i_APCI1710_DisableLatchInterrupt(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_WRITE16BITCOUNTERVALUE: - i_ReturnValue = i_APCI1710_Write16BitCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) data[0], (unsigned int) data[1]); - break; - - case APCI1710_INCCPT_WRITE32BITCOUNTERVALUE: - i_ReturnValue = i_APCI1710_Write32BitCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned int) data[0]); - - break; - - case APCI1710_INCCPT_ENABLEINDEX: - i_APCI1710_EnableIndex(dev, (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_DISABLEINDEX: - i_ReturnValue = i_APCI1710_DisableIndex(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_ENABLECOMPARELOGIC: - i_ReturnValue = i_APCI1710_EnableCompareLogic(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_DISABLECOMPARELOGIC: - i_ReturnValue = i_APCI1710_DisableCompareLogic(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - case APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT: - i_ReturnValue = i_APCI1710_EnableFrequencyMeasurement(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT: - i_ReturnValue = i_APCI1710_DisableFrequencyMeasurement(dev, - (unsigned char) CR_AREF(insn->chanspec)); - break; - - default: - printk("Write Config Parameter Wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableLatchInterrupt | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Enable the latch interrupt from selected module | -| (b_ModulNbr). Each software or hardware latch occur a | -| interrupt. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Interrupt routine not installed see function | -| "i_APCI1710_SetBoardIntRoutine" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - - /********************/ - /* Enable interrupt */ - /********************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 | APCI1710_ENABLE_LATCH_INT; - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableLatchInterrupt | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Disable the latch interrupt from selected module | -| (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Interrupt routine not installed see function | -| "i_APCI1710_SetBoardIntRoutine" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4 & - ((APCI1710_DISABLE_LATCH_INT << 8) | 0xFF), - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - - mdelay(1000); - - /*********************/ - /* Disable interrupt */ - /*********************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & APCI1710_DISABLE_LATCH_INT; - - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Write16BitCounterValue | -| (unsigned char_ b_BoardHandle | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SelectedCounter, | -| unsigned int_ ui_WriteValue) | -+----------------------------------------------------------------------------+ -| Task : Write a 16-Bit value (ui_WriteValue) in to the selected| -| 16-Bit counter (b_SelectedCounter) from selected module| -| (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_SelectedCounter : Selected 16-Bit counter | -| (0 or 1) | -| unsigned int_ ui_WriteValue : 16-Bit write value | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected 16-Bit counter parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_Write16BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_SelectedCounter, unsigned int ui_WriteValue) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /******************************/ - /* Test the counter selection */ - /******************************/ - - if (b_SelectedCounter < 2) { - /*******************/ - /* Write the value */ - /*******************/ - - outl((unsigned int) ((unsigned int) (ui_WriteValue) << (16 * - b_SelectedCounter)), - devpriv->s_BoardInfos.ui_Address + 8 + - (b_SelectedCounter * 4) + - (64 * b_ModulNbr)); - } else { - /**************************************************/ - /* The selected 16-Bit counter parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected 16-Bit counter parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Write32BitCounterValue | -| (unsigned char_ b_BoardHandle | -| unsigned char_ b_ModulNbr, | -| ULONG_ ul_WriteValue) | -+----------------------------------------------------------------------------+ -| Task : Write a 32-Bit value (ui_WriteValue) in to the selected| -| module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| ULONG_ ul_WriteValue : 32-Bit write value | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_Write32BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned int ul_WriteValue) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*******************/ - /* Write the value */ - /*******************/ - - outl(ul_WriteValue, devpriv->s_BoardInfos. - ui_Address + 4 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableIndex (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Enable the INDEX actions | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Index not initialised see function | -| "i_APCI1710_InitIndex" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_EnableIndex(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - unsigned int ul_InterruptLatchReg; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*****************************/ - /* Test if index initialised */ - /*****************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_IndexInit) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 | APCI1710_ENABLE_INDEX; - - ul_InterruptLatchReg = - inl(devpriv->s_BoardInfos.ui_Address + - 24 + (64 * b_ModulNbr)); - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - } else { - /*************************************************************/ - /* Index not initialised see function "i_APCI1710_InitIndex" */ - /*************************************************************/ - - DPRINTK("Index not initialised \n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableIndex (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Disable the INDEX actions | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Index not initialised see function | -| "i_APCI1710_InitIndex" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_DisableIndex(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*****************************/ - /* Test if index initialised */ - /*****************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_IndexInit) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & - APCI1710_DISABLE_INDEX; - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - } else { - /*************************************************************/ - /* Index not initialised see function "i_APCI1710_InitIndex" */ - /*************************************************************/ - - DPRINTK("Index not initialised \n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableCompareLogic | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Enable the 32-Bit compare logic. At that moment that | -| the incremental counter arrive to the compare value a | -| interrupt is generated. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Compare logic not initialised. | -| See function "i_APCI1710_InitCompareLogic" | -| -5: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_EnableCompareLogic(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test if compare logic initialised */ - /*************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_CompareLogicInit == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 | - APCI1710_ENABLE_COMPARE_INT; - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - } else { - /*********************************/ - /* Compare logic not initialised */ - /*********************************/ - - DPRINTK("Compare logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableCompareLogic | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Task : Disable the 32-Bit compare logic. -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : - -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Compare logic not initialised. | -| See function "i_APCI1710_InitCompareLogic" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_DisableCompareLogic(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test if compare logic initialised */ - /*************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_CompareLogicInit == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_DISABLE_COMPARE_INT; - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - } else { - /*********************************/ - /* Compare logic not initialised */ - /*********************************/ - - DPRINTK("Compare logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_EnableFrequencyMeasurement | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr, | - | unsigned char_ b_InterruptEnable) | - +----------------------------------------------------------------------------+ - | Task : Enables the frequency measurement function | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | - | unsigned char_ b_ModulNbr : Number of the module to be | - | configured (0 to 3) | - | unsigned char_ b_InterruptEnable: Enable or disable the | - | interrupt. | - | APCI1710_ENABLE: | - | Enable the interrupt | - | APCI1710_DISABLE: | - | Disable the interrupt | - +----------------------------------------------------------------------------+ - | Output Parameters : - | - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: The selected module number is wrong | - | -3: Counter not initialised see function | - | "i_APCI1710_InitCounter" | - | -4: Frequency measurement logic not initialised. | - | See function "i_APCI1710_InitFrequencyMeasurement" | - | -5: Interrupt parameter is wrong | - | -6: Interrupt function not initialised. | - +----------------------------------------------------------------------------+ - */ - -int i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_InterruptEnable) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /********************************************/ - /* Test if frequency measurement initialised */ - /********************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_FrequencyMeasurementInit == 1) { - /***************************/ - /* Test the interrupt mode */ - /***************************/ - - if ((b_InterruptEnable == APCI1710_DISABLE) || - (b_InterruptEnable == APCI1710_ENABLE)) - { - - /************************************/ - /* Enable the frequency measurement */ - /************************************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 | - APCI1710_ENABLE_FREQUENCY; - - /*********************************************/ - /* Disable or enable the frequency interrupt */ - /*********************************************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_DISABLE_FREQUENCY_INT) - | (b_InterruptEnable << 3); - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos. - ui_Address + 20 + - (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_FrequencyMeasurementEnable = - 1; - } else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue = -5; - } - } else { - /***********************************************/ - /* Frequency measurement logic not initialised */ - /***********************************************/ - - DPRINTK("Frequency measurement logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_DisableFrequencyMeasurement | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr) | - +----------------------------------------------------------------------------+ - | Task : Disables the frequency measurement function | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | - | unsigned char_ b_ModulNbr : Number of the module to be | - | configured (0 to 3) | - +----------------------------------------------------------------------------+ - | Output Parameters : - | - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: The selected module number is wrong | - | -3: Counter not initialised see function | - | "i_APCI1710_InitCounter" | - | -4: Frequency measurement logic not initialised. | - | See function "i_APCI1710_InitFrequencyMeasurement" | - +----------------------------------------------------------------------------+ - */ - -int i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev, unsigned char b_ModulNbr) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /********************************************/ - /* Test if frequency measurement initialised */ - /********************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_FrequencyMeasurementInit == 1) { - /*************************************/ - /* Disable the frequency measurement */ - /*************************************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_DISABLE_FREQUENCY - /* Begin CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */ - & APCI1710_DISABLE_FREQUENCY_INT; - /* End CG 29/06/01 CG 1100/0231 -> 0701/0232 Frequence measure IRQ must be cleared */ - - /***************************/ - /* Write the configuration */ - /***************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - - /*************************************/ - /* Disable the frequency measurement */ - /*************************************/ - - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_FrequencyMeasurementEnable = 0; - } else { - /***********************************************/ - /* Frequency measurement logic not initialised */ - /***********************************************/ - - DPRINTK("Frequency measurement logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/*########################################################################### */ - - /* INSN READ */ - -/*########################################################################### */ - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev,struct comedi_subdevice *s, -struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read and Get functions for INC_CPT | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ -int i_APCI1710_InsnReadINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_ReadType; - int i_ReturnValue = 0; - - ui_ReadType = CR_CHAN(insn->chanspec); - - devpriv->tsk_Current = current; /* Save the current process task structure */ - switch (ui_ReadType) { - case APCI1710_INCCPT_READLATCHREGISTERSTATUS: - i_ReturnValue = i_APCI1710_ReadLatchRegisterStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) CR_RANGE(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_READLATCHREGISTERVALUE: - i_ReturnValue = i_APCI1710_ReadLatchRegisterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]); - printk("Latch Register Value %d\n", data[0]); - break; - - case APCI1710_INCCPT_READ16BITCOUNTERVALUE: - i_ReturnValue = i_APCI1710_Read16BitCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) CR_RANGE(insn->chanspec), (unsigned int *) &data[0]); - break; - - case APCI1710_INCCPT_READ32BITCOUNTERVALUE: - i_ReturnValue = i_APCI1710_Read32BitCounterValue(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned int *) &data[0]); - break; - - case APCI1710_INCCPT_GETINDEXSTATUS: - i_ReturnValue = i_APCI1710_GetIndexStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_GETREFERENCESTATUS: - i_ReturnValue = i_APCI1710_GetReferenceStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_GETUASSTATUS: - i_ReturnValue = i_APCI1710_GetUASStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_GETCBSTATUS: - i_ReturnValue = i_APCI1710_GetCBStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_GET16BITCBSTATUS: - i_ReturnValue = i_APCI1710_Get16BitCBStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char *) &data[0], (unsigned char *) &data[1]); - break; - - case APCI1710_INCCPT_GETUDSTATUS: - i_ReturnValue = i_APCI1710_GetUDStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - - break; - - case APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS: - i_ReturnValue = i_APCI1710_GetInterruptUDLatchedStatus(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char *) &data[0]); - break; - - case APCI1710_INCCPT_READFREQUENCYMEASUREMENT: - i_ReturnValue = i_APCI1710_ReadFrequencyMeasurement(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char *) &data[0], - (unsigned char *) &data[1], (unsigned int *) &data[2]); - break; - - case APCI1710_INCCPT_READINTERRUPT: - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /**************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv-> - s_InterruptParameters. - ui_Read = (devpriv->s_InterruptParameters. - ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - break; - - default: - printk("ReadType Parameter wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; - -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadLatchRegisterStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_LatchReg, | -| unsigned char *_ pb_LatchStatus) | -+----------------------------------------------------------------------------+ -| Task : Read the latch register status from selected module | -| (b_ModulNbr) and selected latch register (b_LatchReg). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_LatchReg : Selected latch register | -| 0 : for the first latch register | -| 1 : for the second latch register | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_LatchStatus : Latch register status. | -| 0 : No latch occur | -| 1 : A software latch occur | -| 2 : A hardware latch occur | -| 3 : A software and hardware | -| latch occur | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected latch register parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_LatchReg, unsigned char *pb_LatchStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_LatchReg; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test the latch register parameter */ - /*************************************/ - - if (b_LatchReg < 2) { - dw_LatchReg = inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - - *pb_LatchStatus = - (unsigned char) ((dw_LatchReg >> (b_LatchReg * - 4)) & 0x3); - } else { - /**************************************************/ - /* The selected latch register parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected latch register parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadLatchRegisterValue | -| (unsigned char_ b_BoardHandle,| -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_LatchReg, | -| PULONG_ pul_LatchValue) | -+----------------------------------------------------------------------------+ -| Task : Read the latch register value from selected module | -| (b_ModulNbr) and selected latch register (b_LatchReg). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_LatchReg : Selected latch register | -| 0 : for the first latch register | -| 1 : for the second latch register | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_LatchValue : Latch register value | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected latch register parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_LatchReg, unsigned int *pul_LatchValue) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************************/ - /* Test the latch register parameter */ - /*************************************/ - - if (b_LatchReg < 2) { - *pul_LatchValue = inl(devpriv->s_BoardInfos. - ui_Address + ((b_LatchReg + 1) * 4) + - (64 * b_ModulNbr)); - - } else { - /**************************************************/ - /* The selected latch register parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected latch register parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Read16BitCounterValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SelectedCounter, | -| unsigned int *_ pui_CounterValue) | -+----------------------------------------------------------------------------+ -| Task : Latch the selected 16-Bit counter (b_SelectedCounter) | -| from selected module (b_ModulNbr) in to the first | -| latch register and return the latched value. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| unsigned char_ b_SelectedCounter : Selected 16-Bit counter | -| (0 or 1) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned int *_ pui_CounterValue : 16-Bit counter value | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: The selected 16-Bit counter parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_Read16BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_SelectedCounter, unsigned int *pui_CounterValue) -{ - int i_ReturnValue = 0; - unsigned int dw_LathchValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /******************************/ - /* Test the counter selection */ - /******************************/ - - if (b_SelectedCounter < 2) { - /*********************/ - /* Latch the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - - /************************/ - /* Read the latch value */ - /************************/ - - dw_LathchValue = inl(devpriv->s_BoardInfos. - ui_Address + 4 + (64 * b_ModulNbr)); - - *pui_CounterValue = - (unsigned int) ((dw_LathchValue >> (16 * - b_SelectedCounter)) & - 0xFFFFU); - } else { - /**************************************************/ - /* The selected 16-Bit counter parameter is wrong */ - /**************************************************/ - - DPRINTK("The selected 16-Bit counter parameter is wrong\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Read32BitCounterValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| PULONG_ pul_CounterValue) | -+----------------------------------------------------------------------------+ -| Task : Latch the 32-Bit counter from selected module | -| (b_ModulNbr) in to the first latch register and return | -| the latched value. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_CounterValue : 32-Bit counter value | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_Read32BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned int *pul_CounterValue) -{ - int i_ReturnValue = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*********************/ - /* Tatch the counter */ - /*********************/ - - outl(1, devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - - /************************/ - /* Read the latch value */ - /************************/ - - *pul_CounterValue = inl(devpriv->s_BoardInfos. - ui_Address + 4 + (64 * b_ModulNbr)); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetIndexStatus (unsigned char_ b_BoardHandle,| -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_IndexStatus)| -+----------------------------------------------------------------------------+ -| Task : Return the index status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_IndexStatus : 0 : No INDEX occur | -| 1 : A INDEX occur | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Index not initialised see function | -| "i_APCI1710_InitIndex" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetIndexStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_IndexStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*****************************/ - /* Test if index initialised */ - /*****************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_IndexInit) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (64 * b_ModulNbr)); - - *pb_IndexStatus = (unsigned char) (dw_StatusReg & 1); - } else { - /*************************************************************/ - /* Index not initialised see function "i_APCI1710_InitIndex" */ - /*************************************************************/ - - DPRINTK("Index not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetReferenceStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_ReferenceStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the reference status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_ReferenceStatus : 0 : No REFERENCE occur | -| 1 : A REFERENCE occur | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Reference not initialised see function | -| "i_APCI1710_InitReference" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetReferenceStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_ReferenceStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*********************************/ - /* Test if reference initialised */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_ReferenceInit) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 24 + (64 * b_ModulNbr)); - - *pb_ReferenceStatus = - (unsigned char) (~dw_StatusReg & 1); - } else { - /*********************************************************************/ - /* Reference not initialised see function "i_APCI1710_InitReference" */ - /*********************************************************************/ - - DPRINTK("Reference not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetUASStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_UASStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the error signal (UAS) status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_UASStatus : 0 : UAS is low "0" | -| 1 : UAS is high "1" | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetUASStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_UASStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 24 + (64 * b_ModulNbr)); - - *pb_UASStatus = (unsigned char) ((dw_StatusReg >> 1) & 1); - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetCBStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_CBStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the counter overflow status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_CBStatus : 0 : Counter no overflow | -| 1 : Counter overflow | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetCBStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_CBStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModulNbr)); - - *pb_CBStatus = (unsigned char) (dw_StatusReg & 1); - - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Get16BitCBStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_CBStatusCounter0, | -| unsigned char *_ pb_CBStatusCounter1) | -+----------------------------------------------------------------------------+ -| Task : Returns the counter overflow (counter initialised to | -| 2*16-bit) status from selected incremental counter | -| module | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_CBStatusCounter0 : 0 : No overflow occur for | -| the first 16-bit | -| counter | -| 1 : Overflow occur for the| -| first 16-bit counter | -| unsigned char *_ pb_CBStatusCounter1 : 0 : No overflow occur for | -| the second 16-bit | -| counter | -| 1 : Overflow occur for the| -| second 16-bit counter | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Counter not initialised to 2*16-bit mode. | -| See function "i_APCI1710_InitCounter" | -| -5: Firmware revision error | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_Get16BitCBStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_CBStatusCounter0, unsigned char *pb_CBStatusCounter1) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*************************/ - /* Test if 2*16-Bit mode */ - /*************************/ - - if ((devpriv->s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 & 0x10) == 0x10) { - /*****************************/ - /* Test the Firmware version */ - /*****************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & 0xFFFF) >= - 0x3136) { - dw_StatusReg = - inl(devpriv->s_BoardInfos. - ui_Address + 16 + - (64 * b_ModulNbr)); - - *pb_CBStatusCounter1 = - (unsigned char) ((dw_StatusReg >> 0) & - 1); - *pb_CBStatusCounter0 = - (unsigned char) ((dw_StatusReg >> 1) & - 1); - } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */ - else { - /****************************/ - /* Firmware revision error */ - /****************************/ - - i_ReturnValue = -5; - } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_BoardInfos.dw_MolduleConfiguration [b_ModulNbr] & 0xFFFF) >= 0x3136) */ - } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */ - else { - /********************************************/ - /* Counter not initialised to 2*16-bit mode */ - /* "i_APCI1710_InitCounter" */ - /********************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -4; - } /* if ((ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & 0x10) == 0x10) */ - } /* if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */ - else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } /* if (ps_APCI1710Variable->s_Board [b_BoardHandle].s_ModuleInfo [b_ModulNbr].s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) */ - } /* if (b_ModulNbr < 4) */ - else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } /* if (b_ModulNbr < 4) */ - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetUDStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_UDStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the counter progress status | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_UDStatus : 0 : Counter progress in the | -| selected mode down | -| 1 : Counter progress in the | -| selected mode up | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetUDStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_UDStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 24 + (64 * b_ModulNbr)); - - *pb_UDStatus = (unsigned char) ((dw_StatusReg >> 2) & 1); - - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetInterruptUDLatchedStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char *_ pb_UDStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the counter progress latched status after a | -| index interrupt occur. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_UDStatus : 0 : Counter progress in the | -| selected mode down | -| 1 : Counter progress in the | -| selected mode up | -| 2 : No index interrupt occur | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: No counter module found | -| -3: Counter not initialised see function | -| "i_APCI1710_InitCounter" | -| -4: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_UDStatus) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /*********************************/ - /* Test if index interrupt occur */ - /*********************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_IndexInterruptOccur == 1) { - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_IndexInterruptOccur = 0; - - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (64 * b_ModulNbr)); - - *pb_UDStatus = (unsigned char) ((dw_StatusReg >> 1) & 1); - } else { - /****************************/ - /* No index interrupt occur */ - /****************************/ - - *pb_UDStatus = 2; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : _INT_ i_APCI1710_ReadFrequencyMeasurement | - | (unsigned char_ b_BoardHandle, | - | unsigned char_ b_ModulNbr, | - | unsigned char *_ pb_Status, | - | PULONG_ pul_ReadValue) | - +----------------------------------------------------------------------------+ - | Task : Returns the status (pb_Status) and the number of | - | increments in the set time. | - | See function " i_APCI1710_InitFrequencyMeasurement " | - +----------------------------------------------------------------------------+ - | Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | - | unsigned char_ b_ModulNbr : Number of the module to be | - | configured (0 to 3) | - +----------------------------------------------------------------------------+ - | Output Parameters : unsigned char *_ pb_Status : Returns the frequency | - | measurement status | - | 0 : Counting cycle not | - | started. | - | 1 : Counting cycle started. | - | 2 : Counting cycle stopped. | - | The measurement cycle is | - | completed. | - | unsigned char *_ pb_UDStatus : 0 : Counter progress in the | - | selected mode down | - | 1 : Counter progress in the | - | selected mode up | - | PULONG_ pul_ReadValue : Return the number of | - | increments in the defined | - | time base. | - +----------------------------------------------------------------------------+ - | Return Value : 0: No error | - | -1: The handle parameter of the board is wrong | - | -2: The selected module number is wrong | - | -3: Counter not initialised see function | - | "i_APCI1710_InitCounter" | - | -4: Frequency measurement logic not initialised. | - | See function "i_APCI1710_InitFrequencyMeasurement" | - +----------------------------------------------------------------------------+ - */ - -int i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_Status, unsigned char *pb_UDStatus, unsigned int *pul_ReadValue) -{ - int i_ReturnValue = 0; - unsigned int ui_16BitValue; - unsigned int dw_StatusReg; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo.s_InitFlag.b_CounterInit == 1) { - /********************************************/ - /* Test if frequency measurement initialised */ - /********************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag.b_FrequencyMeasurementInit == 1) { - /******************/ - /* Test if enable */ - /******************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SiemensCounterInfo. - s_InitFlag. - b_FrequencyMeasurementEnable == 1) { - /*******************/ - /* Read the status */ - /*******************/ - - dw_StatusReg = - inl(devpriv->s_BoardInfos. - ui_Address + 32 + - (64 * b_ModulNbr)); - - /**************************/ - /* Test if frequency stop */ - /**************************/ - - if (dw_StatusReg & 1) { - *pb_Status = 2; - *pb_UDStatus = - (unsigned char) ((dw_StatusReg >> - 1) & 3); - - /******************/ - /* Read the value */ - /******************/ - - *pul_ReadValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 28 + - (64 * b_ModulNbr)); - - if (*pb_UDStatus == 0) { - /*************************/ - /* Test the counter mode */ - /*************************/ - - if ((devpriv->s_ModuleInfo[b_ModulNbr].s_SiemensCounterInfo.s_ModeRegister.s_ByteModeRegister.b_ModeRegister1 & APCI1710_16BIT_COUNTER) == APCI1710_16BIT_COUNTER) { - /****************************************/ - /* Test if 16-bit counter 1 pulse occur */ - /****************************************/ - - if ((*pul_ReadValue & 0xFFFFU) != 0) { - ui_16BitValue - = - (unsigned int) - * - pul_ReadValue - & - 0xFFFFU; - *pul_ReadValue - = - (*pul_ReadValue - & - 0xFFFF0000UL) - | - (0xFFFFU - - - ui_16BitValue); - } - - /****************************************/ - /* Test if 16-bit counter 2 pulse occur */ - /****************************************/ - - if ((*pul_ReadValue & 0xFFFF0000UL) != 0) { - ui_16BitValue - = - (unsigned int) - ( - (*pul_ReadValue - >> - 16) - & - 0xFFFFU); - *pul_ReadValue - = - (*pul_ReadValue - & - 0xFFFFUL) - | - ( - (0xFFFFU - ui_16BitValue) << 16); - } - } else { - if (*pul_ReadValue != 0) { - *pul_ReadValue - = - 0xFFFFFFFFUL - - - *pul_ReadValue; - } - } - } else { - if (*pb_UDStatus == 1) { - /****************************************/ - /* Test if 16-bit counter 2 pulse occur */ - /****************************************/ - - if ((*pul_ReadValue & 0xFFFF0000UL) != 0) { - ui_16BitValue - = - (unsigned int) - ( - (*pul_ReadValue - >> - 16) - & - 0xFFFFU); - *pul_ReadValue - = - (*pul_ReadValue - & - 0xFFFFUL) - | - ( - (0xFFFFU - ui_16BitValue) << 16); - } - } else { - if (*pb_UDStatus - == 2) { - /****************************************/ - /* Test if 16-bit counter 1 pulse occur */ - /****************************************/ - - if ((*pul_ReadValue & 0xFFFFU) != 0) { - ui_16BitValue - = - (unsigned int) - * - pul_ReadValue - & - 0xFFFFU; - *pul_ReadValue - = - (*pul_ReadValue - & - 0xFFFF0000UL) - | - (0xFFFFU - - - ui_16BitValue); - } - } - } - } - } else { - *pb_Status = 1; - *pb_UDStatus = 0; - } - } else { - *pb_Status = 0; - *pb_UDStatus = 0; - } - } else { - /***********************************************/ - /* Frequency measurement logic not initialised */ - /***********************************************/ - - DPRINTK("Frequency measurement logic not initialised\n"); - i_ReturnValue = -4; - } - } else { - /****************************************/ - /* Counter not initialised see function */ - /* "i_APCI1710_InitCounter" */ - /****************************************/ - - DPRINTK("Counter not initialised\n"); - i_ReturnValue = -3; - } - } else { - /*************************************************/ - /* The selected module number parameter is wrong */ - /*************************************************/ - - DPRINTK("The selected module number parameter is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h deleted file mode 100644 index 358298bfc64..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_INCCPT.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_16BIT_COUNTER 0x10 -#define APCI1710_32BIT_COUNTER 0x0 -#define APCI1710_QUADRUPLE_MODE 0x0 -#define APCI1710_DOUBLE_MODE 0x3 -#define APCI1710_SIMPLE_MODE 0xF -#define APCI1710_DIRECT_MODE 0x80 -#define APCI1710_HYSTERESIS_ON 0x60 -#define APCI1710_HYSTERESIS_OFF 0x0 -#define APCI1710_INCREMENT 0x60 -#define APCI1710_DECREMENT 0x0 -#define APCI1710_LATCH_COUNTER 0x1 -#define APCI1710_CLEAR_COUNTER 0x0 -#define APCI1710_LOW 0x0 -#define APCI1710_HIGH 0x1 - -/*********************/ -/* Version 0600-0229 */ -/*********************/ -#define APCI1710_HIGH_EDGE_CLEAR_COUNTER 0x0 -#define APCI1710_HIGH_EDGE_LATCH_COUNTER 0x1 -#define APCI1710_LOW_EDGE_CLEAR_COUNTER 0x2 -#define APCI1710_LOW_EDGE_LATCH_COUNTER 0x3 -#define APCI1710_HIGH_EDGE_LATCH_AND_CLEAR_COUNTER 0x4 -#define APCI1710_LOW_EDGE_LATCH_AND_CLEAR_COUNTER 0x5 -#define APCI1710_SOURCE_0 0x0 -#define APCI1710_SOURCE_1 0x1 - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_ENABLE_LATCH_INT 0x80 -#define APCI1710_DISABLE_LATCH_INT (~APCI1710_ENABLE_LATCH_INT) - -#define APCI1710_INDEX_LATCH_COUNTER 0x10 -#define APCI1710_INDEX_AUTO_MODE 0x8 -#define APCI1710_ENABLE_INDEX 0x4 -#define APCI1710_DISABLE_INDEX (~APCI1710_ENABLE_INDEX) -#define APCI1710_ENABLE_LATCH_AND_CLEAR 0x8 -#define APCI1710_DISABLE_LATCH_AND_CLEAR (~APCI1710_ENABLE_LATCH_AND_CLEAR) -#define APCI1710_SET_LOW_INDEX_LEVEL 0x4 -#define APCI1710_SET_HIGH_INDEX_LEVEL (~APCI1710_SET_LOW_INDEX_LEVEL) -#define APCI1710_INVERT_INDEX_RFERENCE 0x2 -#define APCI1710_DEFAULT_INDEX_RFERENCE (~APCI1710_INVERT_INDEX_RFERENCE) - -#define APCI1710_ENABLE_INDEX_INT 0x1 -#define APCI1710_DISABLE_INDEX_INT (~APCI1710_ENABLE_INDEX_INT) - -#define APCI1710_ENABLE_FREQUENCY 0x4 -#define APCI1710_DISABLE_FREQUENCY (~APCI1710_ENABLE_FREQUENCY) - -#define APCI1710_ENABLE_FREQUENCY_INT 0x8 -#define APCI1710_DISABLE_FREQUENCY_INT (~APCI1710_ENABLE_FREQUENCY_INT) - -#define APCI1710_ENABLE_40MHZ_FREQUENCY 0x40 -#define APCI1710_DISABLE_40MHZ_FREQUENCY (~APCI1710_ENABLE_40MHZ_FREQUENCY) - -#define APCI1710_ENABLE_40MHZ_FILTER 0x80 -#define APCI1710_DISABLE_40MHZ_FILTER (~APCI1710_ENABLE_40MHZ_FILTER) - -#define APCI1710_ENABLE_COMPARE_INT 0x2 -#define APCI1710_DISABLE_COMPARE_INT (~APCI1710_ENABLE_COMPARE_INT) - -#define APCI1710_ENABLE_INDEX_ACTION 0x20 -#define APCI1710_DISABLE_INDEX_ACTION (~APCI1710_ENABLE_INDEX_ACTION) -#define APCI1710_REFERENCE_HIGH 0x40 -#define APCI1710_REFERENCE_LOW (~APCI1710_REFERENCE_HIGH) - -#define APCI1710_TOR_GATE_LOW 0x40 -#define APCI1710_TOR_GATE_HIGH (~APCI1710_TOR_GATE_LOW) - -/* INSN CONFIG */ -#define APCI1710_INCCPT_INITCOUNTER 100 -#define APCI1710_INCCPT_COUNTERAUTOTEST 101 -#define APCI1710_INCCPT_INITINDEX 102 -#define APCI1710_INCCPT_INITREFERENCE 103 -#define APCI1710_INCCPT_INITEXTERNALSTROBE 104 -#define APCI1710_INCCPT_INITCOMPARELOGIC 105 -#define APCI1710_INCCPT_INITFREQUENCYMEASUREMENT 106 - -/* INSN READ */ -#define APCI1710_INCCPT_READLATCHREGISTERSTATUS 200 -#define APCI1710_INCCPT_READLATCHREGISTERVALUE 201 -#define APCI1710_INCCPT_READ16BITCOUNTERVALUE 202 -#define APCI1710_INCCPT_READ32BITCOUNTERVALUE 203 -#define APCI1710_INCCPT_GETINDEXSTATUS 204 -#define APCI1710_INCCPT_GETREFERENCESTATUS 205 -#define APCI1710_INCCPT_GETUASSTATUS 206 -#define APCI1710_INCCPT_GETCBSTATUS 207 -#define APCI1710_INCCPT_GET16BITCBSTATUS 208 -#define APCI1710_INCCPT_GETUDSTATUS 209 -#define APCI1710_INCCPT_GETINTERRUPTUDLATCHEDSTATUS 210 -#define APCI1710_INCCPT_READFREQUENCYMEASUREMENT 211 -#define APCI1710_INCCPT_READINTERRUPT 212 - -/* INSN BITS */ -#define APCI1710_INCCPT_CLEARCOUNTERVALUE 300 -#define APCI1710_INCCPT_CLEARALLCOUNTERVALUE 301 -#define APCI1710_INCCPT_SETINPUTFILTER 302 -#define APCI1710_INCCPT_LATCHCOUNTER 303 -#define APCI1710_INCCPT_SETINDEXANDREFERENCESOURCE 304 -#define APCI1710_INCCPT_SETDIGITALCHLON 305 -#define APCI1710_INCCPT_SETDIGITALCHLOFF 306 - -/* INSN WRITE */ -#define APCI1710_INCCPT_ENABLELATCHINTERRUPT 400 -#define APCI1710_INCCPT_DISABLELATCHINTERRUPT 401 -#define APCI1710_INCCPT_WRITE16BITCOUNTERVALUE 402 -#define APCI1710_INCCPT_WRITE32BITCOUNTERVALUE 403 -#define APCI1710_INCCPT_ENABLEINDEX 404 -#define APCI1710_INCCPT_DISABLEINDEX 405 -#define APCI1710_INCCPT_ENABLECOMPARELOGIC 406 -#define APCI1710_INCCPT_DISABLECOMPARELOGIC 407 -#define APCI1710_INCCPT_ENABLEFREQUENCYMEASUREMENT 408 -#define APCI1710_INCCPT_DISABLEFREQUENCYMEASUREMENT 409 - -/************ Main Functions *************/ -int i_APCI1710_InsnConfigINCCPT(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int * data); - -int i_APCI1710_InsnBitsINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_insn *insn, unsigned int * data); - -int i_APCI1710_InsnWriteINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_insn *insn, unsigned int * data); - -int i_APCI1710_InsnReadINCCPT(struct comedi_device *dev, struct comedi_subdevice * s, - struct comedi_insn *insn, unsigned int * data); - -/*********** Supplementary Functions********/ - -/* INSN CONFIG */ -int i_APCI1710_InitCounter(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_CounterRange, - unsigned char b_FirstCounterModus, - unsigned char b_FirstCounterOption, - unsigned char b_SecondCounterModus, - unsigned char b_SecondCounterOption); - -int i_APCI1710_CounterAutoTest(struct comedi_device *dev, unsigned char * pb_TestStatus); - -int i_APCI1710_InitIndex(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_ReferenceAction, - unsigned char b_IndexOperation, unsigned char b_AutoMode, - unsigned char b_InterruptEnable); - -int i_APCI1710_InitReference(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_ReferenceLevel); - -int i_APCI1710_InitExternalStrobe(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_ExternalStrobe, - unsigned char b_ExternalStrobeLevel); - -int i_APCI1710_InitCompareLogic(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned int ui_CompareValue); - -int i_APCI1710_InitFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PCIInputClock, - unsigned char b_TimingUnity, - unsigned int ul_TimingInterval, - unsigned int *pul_RealTimingInterval); - -/* INSN BITS */ -int i_APCI1710_ClearCounterValue(struct comedi_device *dev, unsigned char b_ModulNbr); - -int i_APCI1710_ClearAllCounterValue(struct comedi_device *dev); - -int i_APCI1710_SetInputFilter(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_PCIInputClock, - unsigned char b_Filter); - -int i_APCI1710_LatchCounter(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_LatchReg); - -int i_APCI1710_SetIndexAndReferenceSource(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_SourceSelection); - -int i_APCI1710_SetDigitalChlOn(struct comedi_device *dev, unsigned char b_ModulNbr); - -int i_APCI1710_SetDigitalChlOff(struct comedi_device *dev, unsigned char b_ModulNbr); - -/* INSN WRITE */ -int i_APCI1710_EnableLatchInterrupt(struct comedi_device *dev, unsigned char b_ModulNbr); - -int i_APCI1710_DisableLatchInterrupt(struct comedi_device *dev, unsigned char b_ModulNbr); - -int i_APCI1710_Write16BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_SelectedCounter, - unsigned int ui_WriteValue); - -int i_APCI1710_Write32BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned int ul_WriteValue); - -int i_APCI1710_EnableIndex(struct comedi_device *dev, unsigned char b_ModulNbr); - -int i_APCI1710_DisableIndex(struct comedi_device *dev, unsigned char b_ModulNbr); - -int i_APCI1710_EnableCompareLogic(struct comedi_device *dev, unsigned char b_ModulNbr); - -int i_APCI1710_DisableCompareLogic(struct comedi_device *dev, unsigned char b_ModulNbr); - -int i_APCI1710_EnableFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_InterruptEnable); - -int i_APCI1710_DisableFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr); - -/* INSN READ */ -int i_APCI1710_ReadLatchRegisterStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_LatchReg, - unsigned char *pb_LatchStatus); - -int i_APCI1710_ReadLatchRegisterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_LatchReg, - unsigned int *pul_LatchValue); - -int i_APCI1710_Read16BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char b_SelectedCounter, - unsigned int *pui_CounterValue); - -int i_APCI1710_Read32BitCounterValue(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned int *pul_CounterValue); - -int i_APCI1710_GetIndexStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_IndexStatus); - -int i_APCI1710_GetReferenceStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_ReferenceStatus); - -int i_APCI1710_GetUASStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_UASStatus); - -int i_APCI1710_GetCBStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_CBStatus); - -int i_APCI1710_Get16BitCBStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_CBStatusCounter0, - unsigned char *pb_CBStatusCounter1); - -int i_APCI1710_GetUDStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_UDStatus); - -int i_APCI1710_GetInterruptUDLatchedStatus(struct comedi_device *dev, - unsigned char b_ModulNbr, unsigned char *pb_UDStatus); - -int i_APCI1710_ReadFrequencyMeasurement(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char *pb_Status, unsigned char *pb_UDStatus, - unsigned int *pul_ReadValue); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c deleted file mode 100644 index 3f9cfa20d88..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.c +++ /dev/null @@ -1,861 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : Inp_CPT.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 pulse encoder module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ - -#include "APCI1710_Inp_cpt.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitPulseEncoder | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PulseEncoderNbr, | -| unsigned char_ b_InputLevelSelection, | -| unsigned char_ b_TriggerOutputAction, | -| ULONG_ ul_StartValue) | -+----------------------------------------------------------------------------+ -| Task : Configure the pulse encoder operating mode selected via| -| b_ModulNbr and b_PulseEncoderNbr. The pulse encoder | -| after each pulse decrement the counter value from 1. | -| | -| You must calling this function be for you call any | -| other function witch access of pulse encoders. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | -| (0 to 3) | -| unsigned char_ b_InputLevelSelection : Input level selection | -| (0 or 1) | -| 0 : Set pulse encoder| -| count the the low| -| level pulse. | -| 1 : Set pulse encoder| -| count the the | -| high level pulse.| -| unsigned char_ b_TriggerOutputAction : Digital TRIGGER output | -| action | -| 0 : No action | -| 1 : Set the trigger | -| output to "1" | -| (high) after the | -| passage from 1 to| -| 0 from pulse | -| encoder. | -| 2 : Set the trigger | -| output to "0" | -| (low) after the | -| passage from 1 to| -| 0 from pulse | -| encoder | -| ULONG_ ul_StartValue : Pulse encoder start value| -| (1 to 4294967295) - b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); - b_PulseEncoderNbr =(unsigned char) data[0]; - b_InputLevelSelection =(unsigned char) data[1]; - b_TriggerOutputAction =(unsigned char) data[2]; - ul_StartValue =(unsigned int) data[3]; - | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module is not a pulse encoder module | -| -3: Pulse encoder selection is wrong | -| -4: Input level selection is wrong | -| -5: Digital TRIGGER output action selection is wrong | -| -6: Pulse encoder start value is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_IntRegister; - - unsigned char b_ModulNbr; - unsigned char b_PulseEncoderNbr; - unsigned char b_InputLevelSelection; - unsigned char b_TriggerOutputAction; - unsigned int ul_StartValue; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_PulseEncoderNbr = (unsigned char) data[0]; - b_InputLevelSelection = (unsigned char) data[1]; - b_TriggerOutputAction = (unsigned char) data[2]; - ul_StartValue = (unsigned int) data[3]; - - i_ReturnValue = insn->n; - - /***********************************/ - /* Test the selected module number */ - /***********************************/ - - if (b_ModulNbr <= 3) { - /*************************/ - /* Test if pulse encoder */ - /*************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - APCI1710_PULSE_ENCODER) == - APCI1710_PULSE_ENCODER) { - /******************************************/ - /* Test the selected pulse encoder number */ - /******************************************/ - - if (b_PulseEncoderNbr <= 3) { - /************************/ - /* Test the input level */ - /************************/ - - if ((b_InputLevelSelection == 0) - || (b_InputLevelSelection == 1)) { - /*******************************************/ - /* Test the ouput TRIGGER action selection */ - /*******************************************/ - - if ((b_TriggerOutputAction <= 2) - || (b_PulseEncoderNbr > 0)) { - if (ul_StartValue > 1) { - - dw_IntRegister = - inl(devpriv-> - s_BoardInfos. - ui_Address + - 20 + - (64 * b_ModulNbr)); - - /***********************/ - /* Set the start value */ - /***********************/ - - outl(ul_StartValue, - devpriv-> - s_BoardInfos. - ui_Address + - (b_PulseEncoderNbr - * 4) + - (64 * b_ModulNbr)); - - /***********************/ - /* Set the input level */ - /***********************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister & - (0xFFFFFFFFUL - - (1UL << (8 + b_PulseEncoderNbr)))) | ((1UL & (~b_InputLevelSelection)) << (8 + b_PulseEncoderNbr)); - - /*******************************/ - /* Test if output trigger used */ - /*******************************/ - - if ((b_TriggerOutputAction > 0) && (b_PulseEncoderNbr > 1)) { - /****************************/ - /* Enable the output action */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - | (1UL - << (4 + b_PulseEncoderNbr)); - - /*********************************/ - /* Set the output TRIGGER action */ - /*********************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - & - (0xFFFFFFFFUL - - - (1UL << (12 + b_PulseEncoderNbr)))) | ((1UL & (b_TriggerOutputAction - 1)) << (12 + b_PulseEncoderNbr)); - } else { - /*****************************/ - /* Disable the output action */ - /*****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - & - (0xFFFFFFFFUL - - - (1UL << (4 + b_PulseEncoderNbr))); - } - - /*************************/ - /* Set the configuration */ - /*************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister, - devpriv-> - s_BoardInfos. - ui_Address + - 20 + - (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - s_PulseEncoderInfo - [b_PulseEncoderNbr]. - b_PulseEncoderInit - = 1; - } else { - /**************************************/ - /* Pulse encoder start value is wrong */ - /**************************************/ - - DPRINTK("Pulse encoder start value is wrong\n"); - i_ReturnValue = -6; - } - } else { - /****************************************************/ - /* Digital TRIGGER output action selection is wrong */ - /****************************************************/ - - DPRINTK("Digital TRIGGER output action selection is wrong\n"); - i_ReturnValue = -5; - } - } else { - /**********************************/ - /* Input level selection is wrong */ - /**********************************/ - - DPRINTK("Input level selection is wrong\n"); - i_ReturnValue = -4; - } - } else { - /************************************/ - /* Pulse encoder selection is wrong */ - /************************************/ - - DPRINTK("Pulse encoder selection is wrong\n"); - i_ReturnValue = -3; - } - } else { - /********************************************/ - /* The module is not a pulse encoder module */ - /********************************************/ - - DPRINTK("The module is not a pulse encoder module\n"); - i_ReturnValue = -2; - } - } else { - /********************************************/ - /* The module is not a pulse encoder module */ - /********************************************/ - - DPRINTK("The module is not a pulse encoder module\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnablePulseEncoder | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PulseEncoderNbr, | -| unsigned char_ b_CycleSelection, | -| unsigned char_ b_InterruptHandling) | -+----------------------------------------------------------------------------+ -| Task : Enableor disable the selected pulse encoder (b_PulseEncoderNbr) | -| from selected module (b_ModulNbr). Each input pulse | -| decrement the pulse encoder counter value from 1. | -| If you enabled the interrupt (b_InterruptHandling), a | -| interrupt is generated when the pulse encoder has run | -| down. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | -| (0 to 3) | -| unsigned char_ b_CycleSelection : APCI1710_CONTINUOUS: | -| Each time the | -| counting value is set| -| on "0", the pulse | -| encoder load the | -| start value after | -| the next pulse. | -| APCI1710_SINGLE: | -| If the counter is set| -| on "0", the pulse | -| encoder is stopped. | -| unsigned char_ b_InterruptHandling : Interrupts can be | -| generated, when the pulse| -| encoder has run down. | -| With this parameter the | -| user decides if | -| interrupts are used or | -| not. | -| APCI1710_ENABLE: | -| Interrupts are enabled | -| APCI1710_DISABLE: | -| Interrupts are disabled - - b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); - b_Action =(unsigned char) data[0]; - b_PulseEncoderNbr =(unsigned char) data[1]; - b_CycleSelection =(unsigned char) data[2]; - b_InterruptHandling =(unsigned char) data[3];| -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection is wrong | -| -3: Pulse encoder selection is wrong | -| -4: Pulse encoder not initialised. | -| See function "i_APCI1710_InitPulseEncoder" | -| -5: Cycle selection mode is wrong | -| -6: Interrupt handling mode is wrong | -| -7: Interrupt routine not installed. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned char b_ModulNbr; - unsigned char b_PulseEncoderNbr; - unsigned char b_CycleSelection; - unsigned char b_InterruptHandling; - unsigned char b_Action; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_Action = (unsigned char) data[0]; - b_PulseEncoderNbr = (unsigned char) data[1]; - b_CycleSelection = (unsigned char) data[2]; - b_InterruptHandling = (unsigned char) data[3]; - - /***********************************/ - /* Test the selected module number */ - /***********************************/ - - if (b_ModulNbr <= 3) { - /******************************************/ - /* Test the selected pulse encoder number */ - /******************************************/ - - if (b_PulseEncoderNbr <= 3) { - /*************************************/ - /* Test if pulse encoder initialised */ - /*************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - s_PulseEncoderInfo[b_PulseEncoderNbr]. - b_PulseEncoderInit == 1) { - switch (b_Action) { - - case APCI1710_ENABLE: - /****************************/ - /* Test the cycle selection */ - /****************************/ - - if (b_CycleSelection == - APCI1710_CONTINUOUS - || b_CycleSelection == - APCI1710_SINGLE) { - /*******************************/ - /* Test the interrupt handling */ - /*******************************/ - - if (b_InterruptHandling == - APCI1710_ENABLE - || b_InterruptHandling - == APCI1710_DISABLE) { - /******************************/ - /* Test if interrupt not used */ - /******************************/ - - if (b_InterruptHandling - == - APCI1710_DISABLE) - { - /*************************/ - /* Disable the interrupt */ - /*************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - & - (0xFFFFFFFFUL - - - (1UL << b_PulseEncoderNbr)); - } else { - - /************************/ - /* Enable the interrupt */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister - | (1UL - << - b_PulseEncoderNbr); - devpriv->tsk_Current = current; /* Save the current process task structure */ - - } - - if (i_ReturnValue >= 0) { - /***********************************/ - /* Enable or disable the interrupt */ - /***********************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_SetRegister, - devpriv-> - s_BoardInfos. - ui_Address - + 20 + - (64 * b_ModulNbr)); - - /****************************/ - /* Enable the pulse encoder */ - /****************************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister - = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister - | (1UL - << - b_PulseEncoderNbr); - - /**********************/ - /* Set the cycle mode */ - /**********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister - = - (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister - & - (0xFFFFFFFFUL - - - (1 << (b_PulseEncoderNbr + 4)))) | ((b_CycleSelection & 1UL) << (4 + b_PulseEncoderNbr)); - - /****************************/ - /* Enable the pulse encoder */ - /****************************/ - - outl(devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister, - devpriv-> - s_BoardInfos. - ui_Address - + 16 + - (64 * b_ModulNbr)); - } - } else { - /************************************/ - /* Interrupt handling mode is wrong */ - /************************************/ - - DPRINTK("Interrupt handling mode is wrong\n"); - i_ReturnValue = -6; - } - } else { - /*********************************/ - /* Cycle selection mode is wrong */ - /*********************************/ - - DPRINTK("Cycle selection mode is wrong\n"); - i_ReturnValue = -5; - } - break; - - case APCI1710_DISABLE: - devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister & - (0xFFFFFFFFUL - - (1UL << b_PulseEncoderNbr)); - - /*****************************/ - /* Disable the pulse encoder */ - /*****************************/ - - outl(devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_ControlRegister, - devpriv->s_BoardInfos. - ui_Address + 16 + - (64 * b_ModulNbr)); - - break; - } /* switch End */ - - } else { - /*********************************/ - /* Pulse encoder not initialised */ - /*********************************/ - - DPRINTK("Pulse encoder not initialised\n"); - i_ReturnValue = -4; - } - } else { - /************************************/ - /* Pulse encoder selection is wrong */ - /************************************/ - - DPRINTK("Pulse encoder selection is wrong\n"); - i_ReturnValue = -3; - } - } else { - /*****************************/ - /* Module selection is wrong */ - /*****************************/ - - DPRINTK("Module selection is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadPulseEncoderStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PulseEncoderNbr, | -| unsigned char *_ pb_Status) | -+----------------------------------------------------------------------------+ -| Task APCI1710_PULSEENCODER_READ : Reads the pulse encoder status - and valuefrom selected pulse | -| encoder (b_PulseEncoderNbr) from selected module | -| (b_ModulNbr). | -+----------------------------------------------------------------------------+ - unsigned char b_Type; data[0] - APCI1710_PULSEENCODER_WRITE - Writes a 32-bit value (ul_WriteValue) into the selected| -| pulse encoder (b_PulseEncoderNbr) from selected module | -| (b_ModulNbr). This operation set the new start pulse | -| encoder value. - APCI1710_PULSEENCODER_READ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| CRAREF() unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| data[1] unsigned char_ b_PulseEncoderNbr : Pulse encoder selection | -| (0 to 3) - APCI1710_PULSEENCODER_WRITE - data[2] ULONG_ ul_WriteValue : 32-bit value to be | -| written | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_Status : Pulse encoder status. | -| 0 : No overflow occur| -| 1 : Overflow occur - PULONG_ pul_ReadValue : Pulse encoder value | | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection is wrong | -| -3: Pulse encoder selection is wrong | -| -4: Pulse encoder not initialised. | -| See function "i_APCI1710_InitPulseEncoder" | -+----------------------------------------------------------------------------+ -*/ - -/*_INT_ i_APCI1710_ReadPulseEncoderStatus (unsigned char_ b_BoardHandle, - unsigned char_ b_ModulNbr, - unsigned char_ b_PulseEncoderNbr, - - unsigned char *_ pb_Status) - */ -int i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusRegister; - unsigned char b_ModulNbr; - unsigned char b_PulseEncoderNbr; - unsigned char *pb_Status; - unsigned char b_Type; - unsigned int *pul_ReadValue; - unsigned int ul_WriteValue; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_Type = (unsigned char) data[0]; - b_PulseEncoderNbr = (unsigned char) data[1]; - pb_Status = (unsigned char *) &data[0]; - pul_ReadValue = (unsigned int *) &data[1]; - - /***********************************/ - /* Test the selected module number */ - /***********************************/ - - if (b_ModulNbr <= 3) { - /******************************************/ - /* Test the selected pulse encoder number */ - /******************************************/ - - if (b_PulseEncoderNbr <= 3) { - /*************************************/ - /* Test if pulse encoder initialised */ - /*************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - s_PulseEncoderInfo[b_PulseEncoderNbr]. - b_PulseEncoderInit == 1) { - - switch (b_Type) { - case APCI1710_PULSEENCODER_READ: - /****************************/ - /* Read the status register */ - /****************************/ - - dw_StatusRegister = - inl(devpriv->s_BoardInfos. - ui_Address + 16 + - (64 * b_ModulNbr)); - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister | - dw_StatusRegister; - - *pb_Status = - (unsigned char) (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister >> (1 + - b_PulseEncoderNbr)) & 1; - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PulseEncoderModuleInfo. - dw_StatusRegister & - (0xFFFFFFFFUL - (1 << (1 + - b_PulseEncoderNbr))); - - /******************/ - /* Read the value */ - /******************/ - - *pul_ReadValue = - inl(devpriv->s_BoardInfos. - ui_Address + - (4 * b_PulseEncoderNbr) + - (64 * b_ModulNbr)); - break; - - case APCI1710_PULSEENCODER_WRITE: - ul_WriteValue = (unsigned int) data[2]; - /*******************/ - /* Write the value */ - /*******************/ - - outl(ul_WriteValue, - devpriv->s_BoardInfos. - ui_Address + - (4 * b_PulseEncoderNbr) + - (64 * b_ModulNbr)); - - } /* end of switch */ - } else { - /*********************************/ - /* Pulse encoder not initialised */ - /*********************************/ - - DPRINTK("Pulse encoder not initialised\n"); - i_ReturnValue = -4; - } - } else { - /************************************/ - /* Pulse encoder selection is wrong */ - /************************************/ - - DPRINTK("Pulse encoder selection is wrong\n"); - i_ReturnValue = -3; - } - } else { - /*****************************/ - /* Module selection is wrong */ - /*****************************/ - - DPRINTK("Module selection is wrong\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -int i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /***************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv->s_InterruptParameters. - ui_Read = (devpriv-> - s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - return insn->n; - -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h deleted file mode 100644 index 31fbb0bec52..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Inp_cpt.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_SINGLE 0 -#define APCI1710_CONTINUOUS 1 - -#define APCI1710_PULSEENCODER_READ 0 -#define APCI1710_PULSEENCODER_WRITE 1 - -int i_APCI1710_InsnConfigInitPulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnWriteEnableDisablePulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -/* - * READ PULSE ENCODER FUNCTIONS - */ -int i_APCI1710_InsnReadInterruptPulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -/* - * WRITE PULSE ENCODER FUNCTIONS - */ -int i_APCI1710_InsnBitsReadWritePulseEncoder(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c deleted file mode 100644 index 8883e666211..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.c +++ /dev/null @@ -1,3588 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : PWM.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 Wulse wide modulation module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +-----------------------------------------------------------------------+ - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ - -#include "APCI1710_Pwm.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnConfigPWM(struct comedi_device *dev, -struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Pwm Init and Get Pwm Initialisation | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigPWM(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned char b_ConfigType; - int i_ReturnValue = 0; - b_ConfigType = CR_CHAN(insn->chanspec); - - switch (b_ConfigType) { - case APCI1710_PWM_INIT: - i_ReturnValue = i_APCI1710_InitPWM(dev, (unsigned char) CR_AREF(insn->chanspec), /* b_ModulNbr */ - (unsigned char) data[0], /* b_PWM */ - (unsigned char) data[1], /* b_ClockSelection */ - (unsigned char) data[2], /* b_TimingUnit */ - (unsigned int) data[3], /* ul_LowTiming */ - (unsigned int) data[4], /* ul_HighTiming */ - (unsigned int *) &data[0], /* pul_RealLowTiming */ - (unsigned int *) &data[1] /* pul_RealHighTiming */ - ); - break; - - case APCI1710_PWM_GETINITDATA: - i_ReturnValue = i_APCI1710_GetPWMInitialisation(dev, (unsigned char) CR_AREF(insn->chanspec), /* b_ModulNbr */ - (unsigned char) data[0], /* b_PWM */ - (unsigned char *) &data[0], /* pb_TimingUnit */ - (unsigned int *) &data[1], /* pul_LowTiming */ - (unsigned int *) &data[2], /* pul_HighTiming */ - (unsigned char *) &data[3], /* pb_StartLevel */ - (unsigned char *) &data[4], /* pb_StopMode */ - (unsigned char *) &data[5], /* pb_StopLevel */ - (unsigned char *) &data[6], /* pb_ExternGate */ - (unsigned char *) &data[7], /* pb_InterruptEnable */ - (unsigned char *) &data[8] /* pb_Enable */ - ); - break; - - default: - printk(" Config Parameter Wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitPWM | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char_ b_ClockSelection, | -| unsigned char_ b_TimingUnit, | -| ULONG_ ul_LowTiming, | -| ULONG_ ul_HighTiming, | -| PULONG_ pul_RealLowTiming, | -| PULONG_ pul_RealHighTiming) | -+----------------------------------------------------------------------------+ -| Task : Configure the selected PWM (b_PWM) from selected module| -| (b_ModulNbr). The ul_LowTiming, ul_HighTiming and | -| ul_TimingUnit determine the low/high timing base for | -| the period. pul_RealLowTiming, pul_RealHighTiming | -| return the real timing value. | -| You must calling this function be for you call any | -| other function witch access of the PWM. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure| -| (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1). | -| unsigned char_ b_ClockSelection : Selection from PCI bus | -| clock | -| - APCI1710_30MHZ : | -| The PC have a 30 MHz | -| PCI bus clock | -| - APCI1710_33MHZ : | -| The PC have a 33 MHz | -| PCI bus clock | -| - APCI1710_40MHZ | -| The APCI-1710 have a | -| integrated 40Mhz | -| quartz. | -| unsigned char_ b_TimingUnit : Base timing Unit (0 to 4) | -| 0 : ns | -| 1 : æs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| ULONG_ ul_LowTiming : Low base timing value. | -| ULONG_ ul_HighTiming : High base timing value. | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_RealLowTiming : Real low base timing | -| value. | -| PULONG_ pul_RealHighTiming : Real high base timing | -| value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: The selected input clock is wrong | -| -6: Timing Unit selection is wrong | -| -7: Low base timing selection is wrong | -| -8: High base timing selection is wrong | -| -9: You can not used the 40MHz clock selection with | -| this board | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InitPWM(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char b_ClockSelection, - unsigned char b_TimingUnit, - unsigned int ul_LowTiming, - unsigned int ul_HighTiming, - unsigned int *pul_RealLowTiming, unsigned int *pul_RealHighTiming) -{ - int i_ReturnValue = 0; - unsigned int ul_LowTimerValue = 0; - unsigned int ul_HighTimerValue = 0; - unsigned int dw_Command; - double d_RealLowTiming = 0; - double d_RealHighTiming = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /******************/ - /* Test the clock */ - /******************/ - - if ((b_ClockSelection == APCI1710_30MHZ) || - (b_ClockSelection == APCI1710_33MHZ) || - (b_ClockSelection == APCI1710_40MHZ)) { - /************************/ - /* Test the timing unit */ - /************************/ - - if (b_TimingUnit <= 4) { - /*********************************/ - /* Test the low timing selection */ - /*********************************/ - - if (((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 266) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571230650UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571230UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= 9UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 242) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 519691043UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 519691UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 520UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= 8UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 200) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429496729UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429496UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 7UL))) { - /**********************************/ - /* Test the High timing selection */ - /**********************************/ - - if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) { - /**************************/ - /* Test the board version */ - /**************************/ - - if (((b_ClockSelection == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_ClockSelection != APCI1710_40MHZ)) { - - /************************************/ - /* Calculate the low division fator */ - /************************************/ - - fpu_begin - (); - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (0.00025 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (0.00025 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (0.00025 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (0.25 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (0.25 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - ( - (double) - 0.25 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - ul_LowTiming - * - (250.0 - * - b_ClockSelection); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250.0 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (250.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - ( - (ul_LowTiming - * - 60) - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60; - d_RealLowTiming - = - ( - (double) - ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60.0; - - if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealLowTiming + 0.5)) { - *pul_RealLowTiming - = - *pul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - } - - /*************************************/ - /* Calculate the high division fator */ - /*************************************/ - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (0.00025 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (0.00025 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (0.00025 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (0.25 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (0.25 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - ( - (double) - 0.25 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - ul_HighTiming - * - (250.0 - * - b_ClockSelection); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250.0 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (250.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - ( - (ul_HighTiming - * - 60) - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - *pul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60; - d_RealHighTiming - = - ( - (double) - ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60.0; - - if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)*pul_RealHighTiming + 0.5)) { - *pul_RealHighTiming - = - *pul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - } - - fpu_end(); - /****************************/ - /* Save the clock selection */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - b_ClockSelection - = - b_ClockSelection; - - /************************/ - /* Save the timing unit */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - b_TimingUnit - = - b_TimingUnit; - - /****************************/ - /* Save the low base timing */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - d_LowTiming - = - d_RealLowTiming; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - ul_RealLowTiming - = - *pul_RealLowTiming; - - /****************************/ - /* Save the high base timing */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - d_HighTiming - = - d_RealHighTiming; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - ul_RealHighTiming - = - *pul_RealHighTiming; - - /************************/ - /* Write the low timing */ - /************************/ - - outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /*************************/ - /* Write the high timing */ - /*************************/ - - outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /***************************/ - /* Set the clock selection */ - /***************************/ - - dw_Command - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 8 - + - (20 * b_PWM) + (64 * b_ModulNbr)); - - dw_Command - = - dw_Command - & - 0x7F; - - if (b_ClockSelection == APCI1710_40MHZ) { - dw_Command - = - dw_Command - | - 0x80; - } - - /***************************/ - /* Set the clock selection */ - /***************************/ - - outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /*************/ - /* PWM init. */ - /*************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - b_PWMInit - = - 1; - } else { - /***************************************************/ - /* You can not used the 40MHz clock selection with */ - /* this board */ - /***************************************************/ - DPRINTK("You can not used the 40MHz clock selection with this board\n"); - i_ReturnValue - = - -9; - } - } else { - /***************************************/ - /* High base timing selection is wrong */ - /***************************************/ - DPRINTK("High base timing selection is wrong\n"); - i_ReturnValue = - -8; - } - } else { - /**************************************/ - /* Low base timing selection is wrong */ - /**************************************/ - DPRINTK("Low base timing selection is wrong\n"); - i_ReturnValue = -7; - } - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - else { - /**********************************/ - /* Timing unit selection is wrong */ - /**********************************/ - DPRINTK("Timing unit selection is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - } /* if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */ - else { - /*******************************/ - /* The selected clock is wrong */ - /*******************************/ - DPRINTK("The selected clock is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_ClockSelection == APCI1710_30MHZ) || (b_ClockSelection == APCI1710_33MHZ) || (b_ClockSelection == APCI1710_40MHZ)) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetPWMInitialisation | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char *_ pb_TimingUnit, | -| PULONG_ pul_LowTiming, | -| PULONG_ pul_HighTiming, | -| unsigned char *_ pb_StartLevel, | -| unsigned char *_ pb_StopMode, | -| unsigned char *_ pb_StopLevel, | -| unsigned char *_ pb_ExternGate, | -| unsigned char *_ pb_InterruptEnable, | -| unsigned char *_ pb_Enable) | -+----------------------------------------------------------------------------+ -| Task : Return the PWM (b_PWM) initialisation from selected | -| module (b_ModulNbr). You must calling the | -| "i_APCI1710_InitPWM" function be for you call this | -| function. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TimingUnit : Base timing Unit (0 to 4) | -| 0 : ns | -| 1 : æs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| PULONG_ pul_LowTiming : Low base timing value. | -| PULONG_ pul_HighTiming : High base timing value. | -| unsigned char *_ pb_StartLevel : Start period level | -| selection | -| 0 : The period start | -| with a low level | -| 1 : The period start | -| with a high level| -| unsigned char *_ pb_StopMode : Stop mode selection | -| 0 : The PWM is stopped | -| directly after the | -| "i_APCI1710_DisablePWM"| -| function and break the| -| last period | -| 1 : After the | -| "i_APCI1710_DisablePWM"| -| function the PWM is | -| stopped at the end | -| from last period cycle| -| unsigned char *_ pb_StopLevel : Stop PWM level selection | -| 0 : The output signal | -| keep the level after| -| the | -| "i_APCI1710_DisablePWM"| -| function | -| 1 : The output signal is| -| set to low after the| -| "i_APCI1710_DisablePWM"| -| function | -| 2 : The output signal is| -| set to high after | -| the | -| "i_APCI1710_DisablePWM"| -| function | -| unsigned char *_ pb_ExternGate : Extern gate action | -| selection | -| 0 : Extern gate signal | -| not used. | -| 1 : Extern gate signal | -| used. | -| unsigned char *_ pb_InterruptEnable : Enable or disable the PWM | -| interrupt. | -| - APCI1710_ENABLE : | -| Enable the PWM interrupt| -| A interrupt occur after | -| each period | -| - APCI1710_DISABLE : | -| Disable the PWM | -| interrupt | -| unsigned char *_ pb_Enable : Indicate if the PWM is | -| enabled or no | -| 0 : PWM not enabled | -| 1 : PWM enabled | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised see function | -| "i_APCI1710_InitPWM" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_GetPWMInitialisation(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char *pb_TimingUnit, - unsigned int *pul_LowTiming, - unsigned int *pul_HighTiming, - unsigned char *pb_StartLevel, - unsigned char *pb_StopMode, - unsigned char *pb_StopLevel, - unsigned char *pb_ExternGate, unsigned char *pb_InterruptEnable, unsigned char *pb_Enable) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_Command; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /***********************/ - /* Read the low timing */ - /***********************/ - - *pul_LowTiming = - inl(devpriv->s_BoardInfos. - ui_Address + 0 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - /************************/ - /* Read the high timing */ - /************************/ - - *pul_HighTiming = - inl(devpriv->s_BoardInfos. - ui_Address + 4 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - /********************/ - /* Read the command */ - /********************/ - - dw_Command = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - *pb_StartLevel = - (unsigned char) ((dw_Command >> 5) & 1); - *pb_StopMode = - (unsigned char) ((dw_Command >> 0) & 1); - *pb_StopLevel = - (unsigned char) ((dw_Command >> 1) & 1); - *pb_ExternGate = - (unsigned char) ((dw_Command >> 4) & 1); - *pb_InterruptEnable = - (unsigned char) ((dw_Command >> 3) & 1); - - if (*pb_StopLevel) { - *pb_StopLevel = - *pb_StopLevel + - (unsigned char) ((dw_Command >> - 2) & 1); - } - - /********************/ - /* Read the command */ - /********************/ - - dw_Command = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - *pb_Enable = - (unsigned char) ((dw_Command >> 0) & 1); - - *pb_TimingUnit = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo[b_PWM].b_TimingUnit; - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - DPRINTK("PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name :INT i_APCI1710_InsnWritePWM(struct comedi_device *dev, -struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Pwm Enable Disable and Set New Timing | -+----------------------------------------------------------------------------+ -| Input Parameters : -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnWritePWM(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned char b_WriteType; - int i_ReturnValue = 0; - b_WriteType = CR_CHAN(insn->chanspec); - - switch (b_WriteType) { - case APCI1710_PWM_ENABLE: - i_ReturnValue = i_APCI1710_EnablePWM(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], - (unsigned char) data[2], - (unsigned char) data[3], (unsigned char) data[4], (unsigned char) data[5]); - break; - - case APCI1710_PWM_DISABLE: - i_ReturnValue = i_APCI1710_DisablePWM(dev, - (unsigned char) CR_AREF(insn->chanspec), (unsigned char) data[0]); - break; - - case APCI1710_PWM_NEWTIMING: - i_ReturnValue = i_APCI1710_SetNewPWMTiming(dev, - (unsigned char) CR_AREF(insn->chanspec), - (unsigned char) data[0], - (unsigned char) data[1], (unsigned int) data[2], (unsigned int) data[3]); - break; - - default: - printk("Write Config Parameter Wrong\n"); - } - - if (i_ReturnValue >= 0) - i_ReturnValue = insn->n; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnablePWM | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char_ b_StartLevel, | -| unsigned char_ b_StopMode, | -| unsigned char_ b_StopLevel, | -| unsigned char_ b_ExternGate, | -| unsigned char_ b_InterruptEnable) | -+----------------------------------------------------------------------------+ -| Task : Enable the selected PWM (b_PWM) from selected module | -| (b_ModulNbr). You must calling the "i_APCI1710_InitPWM"| -| function be for you call this function. | -| If you enable the PWM interrupt, the PWM generate a | -| interrupt after each period. | -| See function "i_APCI1710_SetBoardIntRoutineX" and the | -| Interrupt mask description chapter. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number | -| (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1) | -| unsigned char_ b_StartLevel : Start period level selection | -| 0 : The period start with a | -| low level | -| 1 : The period start with a | -| high level | -| unsigned char_ b_StopMode : Stop mode selection | -| 0 : The PWM is stopped | -| directly after the | -| "i_APCI1710_DisablePWM" | -| function and break the | -| last period | -| 1 : After the | -| "i_APCI1710_DisablePWM" | -| function the PWM is | -| stopped at the end from| -| last period cycle. | -| unsigned char_ b_StopLevel : Stop PWM level selection | -| 0 : The output signal keep | -| the level after the | -| "i_APCI1710_DisablePWM" | -| function | -| 1 : The output signal is set| -| to low after the | -| "i_APCI1710_DisablePWM" | -| function | -| 2 : The output signal is set| -| to high after the | -| "i_APCI1710_DisablePWM" | -| function | -| unsigned char_ b_ExternGate : Extern gate action selection | -| 0 : Extern gate signal not | -| used. | -| 1 : Extern gate signal used.| -| unsigned char_ b_InterruptEnable : Enable or disable the PWM | -| interrupt. | -| - APCI1710_ENABLE : | -| Enable the PWM interrupt | -| A interrupt occur after | -| each period | -| - APCI1710_DISABLE : | -| Disable the PWM interrupt | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised see function | -| "i_APCI1710_InitPWM" | -| -6: PWM start level selection is wrong | -| -7: PWM stop mode selection is wrong | -| -8: PWM stop level selection is wrong | -| -9: Extern gate signal selection is wrong | -| -10: Interrupt parameter is wrong | -| -11: Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_EnablePWM(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char b_StartLevel, - unsigned char b_StopMode, - unsigned char b_StopLevel, unsigned char b_ExternGate, unsigned char b_InterruptEnable) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_Command; - - devpriv->tsk_Current = current; /* Save the current process task structure */ - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /**********************************/ - /* Test the start level selection */ - /**********************************/ - - if (b_StartLevel <= 1) { - /**********************/ - /* Test the stop mode */ - /**********************/ - - if (b_StopMode <= 1) { - /***********************/ - /* Test the stop level */ - /***********************/ - - if (b_StopLevel <= 2) { - /*****************************/ - /* Test the extern gate mode */ - /*****************************/ - - if (b_ExternGate - <= 1) { - /*****************************/ - /* Test the interrupt action */ - /*****************************/ - - if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) { - /******************************************/ - /* Test if interrupt function initialised */ - /******************************************/ - - /********************/ - /* Read the command */ - /********************/ - - dw_Command - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 8 - + - (20 * b_PWM) + (64 * b_ModulNbr)); - - dw_Command - = - dw_Command - & - 0x80; - - /********************/ - /* Make the command */ - /********************/ - - dw_Command - = - dw_Command - | - b_StopMode - | - (b_InterruptEnable - << - 3) - | - (b_ExternGate - << - 4) - | - (b_StartLevel - << - 5); - - if (b_StopLevel & 3) { - dw_Command - = - dw_Command - | - 2; - - if (b_StopLevel & 2) { - dw_Command - = - dw_Command - | - 4; - } - } - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - b_InterruptEnable - = - b_InterruptEnable; - - /*******************/ - /* Set the command */ - /*******************/ - - outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 8 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /******************/ - /* Enable the PWM */ - /******************/ - outl(1, devpriv->s_BoardInfos.ui_Address + 12 + (20 * b_PWM) + (64 * b_ModulNbr)); - } /* if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */ - else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue - = - -10; - } /* if (b_InterruptEnable == APCI1710_ENABLE || b_InterruptEnable == APCI1710_DISABLE) */ - } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ - else { - /*****************************************/ - /* Extern gate signal selection is wrong */ - /*****************************************/ - DPRINTK("Extern gate signal selection is wrong\n"); - i_ReturnValue - = - -9; - } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ - } /* if (b_StopLevel >= 0 && b_StopLevel <= 2) */ - else { - /*************************************/ - /* PWM stop level selection is wrong */ - /*************************************/ - DPRINTK("PWM stop level selection is wrong\n"); - i_ReturnValue = - -8; - } /* if (b_StopLevel >= 0 && b_StopLevel <= 2) */ - } /* if (b_StopMode >= 0 && b_StopMode <= 1) */ - else { - /************************************/ - /* PWM stop mode selection is wrong */ - /************************************/ - DPRINTK("PWM stop mode selection is wrong\n"); - i_ReturnValue = -7; - } /* if (b_StopMode >= 0 && b_StopMode <= 1) */ - } /* if (b_StartLevel >= 0 && b_StartLevel <= 1) */ - else { - /**************************************/ - /* PWM start level selection is wrong */ - /**************************************/ - DPRINTK("PWM start level selection is wrong\n"); - i_ReturnValue = -6; - } /* if (b_StartLevel >= 0 && b_StartLevel <= 1) */ - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - DPRINTK("PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisablePWM (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM) | -+----------------------------------------------------------------------------+ -| Task : Disable the selected PWM (b_PWM) from selected module | -| (b_ModulNbr). The output signal level depend of the | -| initialisation by the "i_APCI1710_EnablePWM". | -| See the b_StartLevel, b_StopMode and b_StopLevel | -| parameters from this function. | -+----------------------------------------------------------------------------+ -| Input Parameters :BYTE_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1) | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised see function | -| "i_APCI1710_InitPWM" | -| -6: PWM not enabled see function | -| "i_APCI1710_EnablePWM" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_DisablePWM(struct comedi_device *dev, unsigned char b_ModulNbr, unsigned char b_PWM) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /***********************/ - /* Test if PWM enabled */ - /***********************/ - - if (dw_Status & 0x1) { - /*******************/ - /* Disable the PWM */ - /*******************/ - outl(0, devpriv->s_BoardInfos. - ui_Address + 12 + - (20 * b_PWM) + - (64 * b_ModulNbr)); - } /* if (dw_Status & 0x1) */ - else { - /*******************/ - /* PWM not enabled */ - /*******************/ - DPRINTK("PWM not enabled\n"); - i_ReturnValue = -6; - } /* if (dw_Status & 0x1) */ - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - DPRINTK(" PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetNewPWMTiming | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char_ b_ClockSelection, | -| unsigned char_ b_TimingUnit, | -| ULONG_ ul_LowTiming, | -| ULONG_ ul_HighTiming) | -+----------------------------------------------------------------------------+ -| Task : Set a new timing. The ul_LowTiming, ul_HighTiming and | -| ul_TimingUnit determine the low/high timing base for | -| the period. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Module number to configure| -| (0 to 3) | -| unsigned char_ b_PWM : Selected PWM (0 or 1). | -| unsigned char_ b_TimingUnit : Base timing Unit (0 to 4) | -| 0 : ns | -| 1 : æs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| ULONG_ ul_LowTiming : Low base timing value. | -| ULONG_ ul_HighTiming : High base timing value. | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised | -| -6: Timing Unit selection is wrong | -| -7: Low base timing selection is wrong | -| -8: High base timing selection is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_SetNewPWMTiming(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, unsigned char b_TimingUnit, unsigned int ul_LowTiming, unsigned int ul_HighTiming) -{ - unsigned char b_ClockSelection; - int i_ReturnValue = 0; - unsigned int ul_LowTimerValue = 0; - unsigned int ul_HighTimerValue = 0; - unsigned int ul_RealLowTiming = 0; - unsigned int ul_RealHighTiming = 0; - unsigned int dw_Status; - unsigned int dw_Command; - double d_RealLowTiming = 0; - double d_RealHighTiming = 0; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - b_ClockSelection = devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_PWMModuleInfo. - b_ClockSelection; - - /************************/ - /* Test the timing unit */ - /************************/ - - if (b_TimingUnit <= 4) { - /*********************************/ - /* Test the low timing selection */ - /*********************************/ - - if (((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 266) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571230650UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571230UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 571UL)) - || ((b_ClockSelection == - APCI1710_30MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= 9UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 242) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 519691043UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 519691UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 520UL)) - || ((b_ClockSelection == - APCI1710_33MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= 8UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 0) - && (ul_LowTiming - >= 200) - && (ul_LowTiming - <= - 0xFFFFFFFFUL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 1) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429496729UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 2) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429496UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 3) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 429UL)) - || ((b_ClockSelection == - APCI1710_40MHZ) - && (b_TimingUnit - == 4) - && (ul_LowTiming - >= 1) - && (ul_LowTiming - <= - 7UL))) { - /**********************************/ - /* Test the High timing selection */ - /**********************************/ - - if (((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 266) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230650UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571230UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 571UL)) || ((b_ClockSelection == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 9UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 242) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691043UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 519691UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 520UL)) || ((b_ClockSelection == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 8UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_HighTiming >= 200) && (ul_HighTiming <= 0xFFFFFFFFUL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496729UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429496UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_HighTiming >= 1) && (ul_HighTiming <= 429UL)) || ((b_ClockSelection == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_HighTiming >= 1) && (ul_HighTiming <= 7UL))) { - /************************************/ - /* Calculate the low division fator */ - /************************************/ - - fpu_begin(); - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (0.00025 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (0.00025 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (0.00025 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (0.25 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (0.25 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - ( - (double) - 0.25 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - ul_LowTiming - * - (250.0 - * - b_ClockSelection); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250.0 * (double)b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (250.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - (ul_LowTiming - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_LowTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)); - d_RealLowTiming - = - (double) - ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_LowTimerValue - = - (unsigned int) - ( - (ul_LowTiming - * - 60) - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_LowTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_LowTimerValue + 0.5))) { - ul_LowTimerValue - = - ul_LowTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealLowTiming - = - (unsigned int) - (ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60; - d_RealLowTiming - = - ( - (double) - ul_LowTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60.0; - - if ((double)(((double)ul_LowTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealLowTiming + 0.5)) { - ul_RealLowTiming - = - ul_RealLowTiming - + - 1; - } - - ul_LowTiming - = - ul_LowTiming - - - 1; - ul_LowTimerValue - = - ul_LowTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_LowTimerValue - = - (unsigned int) - ( - (double) - (ul_LowTimerValue) - * - 1.007752288); - } - - break; - } - - /*************************************/ - /* Calculate the high division fator */ - /*************************************/ - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (0.00025 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (0.00025 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (0.00025 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (0.00025 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (0.00025 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (0.25 * b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (0.25 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (0.25 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - ( - (double) - 0.25 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (0.25 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - ul_HighTiming - * - (250.0 - * - b_ClockSelection); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (250.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250.0 * (double)b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (250.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (250.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - (ul_HighTiming - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_HighTiming * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)); - d_RealHighTiming - = - (double) - ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection); - - if ((double)((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_HighTimerValue - = - (unsigned int) - ( - (ul_HighTiming - * - 60) - * - (250000.0 - * - b_ClockSelection)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_HighTiming * 60.0) * (250000.0 * (double)b_ClockSelection)) >= ((double)((double)ul_HighTimerValue + 0.5))) { - ul_HighTimerValue - = - ul_HighTimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealHighTiming - = - (unsigned int) - (ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60; - d_RealHighTiming - = - ( - (double) - ul_HighTimerValue - / - (250000.0 - * - (double) - b_ClockSelection)) - / - 60.0; - - if ((double)(((double)ul_HighTimerValue / (250000.0 * (double)b_ClockSelection)) / 60.0) >= (double)((double)ul_RealHighTiming + 0.5)) { - ul_RealHighTiming - = - ul_RealHighTiming - + - 1; - } - - ul_HighTiming - = - ul_HighTiming - - - 1; - ul_HighTimerValue - = - ul_HighTimerValue - - - 2; - - if (b_ClockSelection != APCI1710_40MHZ) { - ul_HighTimerValue - = - (unsigned int) - ( - (double) - (ul_HighTimerValue) - * - 1.007752288); - } - - break; - } - - fpu_end(); - - /************************/ - /* Save the timing unit */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - b_TimingUnit - = - b_TimingUnit; - - /****************************/ - /* Save the low base timing */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - d_LowTiming - = - d_RealLowTiming; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - ul_RealLowTiming - = - ul_RealLowTiming; - - /****************************/ - /* Save the high base timing */ - /****************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - d_HighTiming - = - d_RealHighTiming; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_PWMModuleInfo. - s_PWMInfo - [b_PWM]. - ul_RealHighTiming - = - ul_RealHighTiming; - - /************************/ - /* Write the low timing */ - /************************/ - - outl(ul_LowTimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /*************************/ - /* Write the high timing */ - /*************************/ - - outl(ul_HighTimerValue, devpriv->s_BoardInfos.ui_Address + 4 + (20 * b_PWM) + (64 * b_ModulNbr)); - - /***************************/ - /* Set the clock selection */ - /***************************/ - - dw_Command = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + 8 + - (20 * b_PWM) + (64 * b_ModulNbr)); - - dw_Command = - dw_Command - & 0x7F; - - if (b_ClockSelection == APCI1710_40MHZ) { - dw_Command - = - dw_Command - | - 0x80; - } - - /***************************/ - /* Set the clock selection */ - /***************************/ - - outl(dw_Command, - devpriv-> - s_BoardInfos. - ui_Address - + 8 + - (20 * b_PWM) + (64 * b_ModulNbr)); - } else { - /***************************************/ - /* High base timing selection is wrong */ - /***************************************/ - DPRINTK("High base timing selection is wrong\n"); - i_ReturnValue = - -8; - } - } else { - /**************************************/ - /* Low base timing selection is wrong */ - /**************************************/ - DPRINTK("Low base timing selection is wrong\n"); - i_ReturnValue = -7; - } - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - else { - /**********************************/ - /* Timing unit selection is wrong */ - /**********************************/ - DPRINTK("Timing unit selection is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - DPRINTK("PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetPWMStatus | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PWM, | -| unsigned char *_ pb_PWMOutputStatus, | -| unsigned char *_ pb_ExternGateStatus) | -+----------------------------------------------------------------------------+ -| Task : Return the status from selected PWM (b_PWM) from | -| selected module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_PWM : Selected PWM (0 or 1) | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) - b_ModulNbr =(unsigned char) CR_AREF(insn->chanspec); - b_PWM =(unsigned char) data[0]; - - | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_PWMOutputStatus : Return the PWM output | -| level status. | -| 0 : The PWM output level| -| is low. | -| 1 : The PWM output level| -| is high. | -| unsigned char *_ pb_ExternGateStatus : Return the extern gate | -| level status. | -| 0 : The extern gate is | -| low. | -| 1 : The extern gate is | -| high. - pb_PWMOutputStatus =(unsigned char *) data[0]; - pb_ExternGateStatus =(unsigned char *) data[1]; | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a PWM module | -| -4: PWM selection is wrong | -| -5: PWM not initialised see function | -| "i_APCI1710_InitPWM" | -| -6: PWM not enabled see function "i_APCI1710_EnablePWM"| -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - - unsigned char b_ModulNbr; - unsigned char b_PWM; - unsigned char *pb_PWMOutputStatus; - unsigned char *pb_ExternGateStatus; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_PWM = (unsigned char) CR_CHAN(insn->chanspec); - pb_PWMOutputStatus = (unsigned char *) &data[0]; - pb_ExternGateStatus = (unsigned char *) &data[1]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***************/ - /* Test if PWM */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_PWM) { - /**************************/ - /* Test the PWM selection */ - /**************************/ - - if (b_PWM <= 1) { - /***************************/ - /* Test if PWM initialised */ - /***************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (20 * b_PWM) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /***********************/ - /* Test if PWM enabled */ - /***********************/ - - if (dw_Status & 0x1) { - *pb_PWMOutputStatus = - (unsigned char) ((dw_Status >> 7) - & 1); - *pb_ExternGateStatus = - (unsigned char) ((dw_Status >> 6) - & 1); - } /* if (dw_Status & 0x1) */ - else { - /*******************/ - /* PWM not enabled */ - /*******************/ - - DPRINTK("PWM not enabled \n"); - i_ReturnValue = -6; - } /* if (dw_Status & 0x1) */ - } /* if (dw_Status & 0x10) */ - else { - /***********************/ - /* PWM not initialised */ - /***********************/ - - DPRINTK("PWM not initialised\n"); - i_ReturnValue = -5; - } /* if (dw_Status & 0x10) */ - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - else { - /******************************/ - /* Tor PWM selection is wrong */ - /******************************/ - - DPRINTK("Tor PWM selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_PWM >= 0 && b_PWM <= 1) */ - } else { - /**********************************/ - /* The module is not a PWM module */ - /**********************************/ - - DPRINTK("The module is not a PWM module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -int i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /**************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv-> - s_InterruptParameters. - ui_Read = (devpriv-> - s_InterruptParameters.ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - return insn->n; - -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h deleted file mode 100644 index d8ad0b9cf50..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Pwm.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_PWM_INIT 0 -#define APCI1710_PWM_GETINITDATA 1 - -#define APCI1710_PWM_DISABLE 0 -#define APCI1710_PWM_ENABLE 1 -#define APCI1710_PWM_NEWTIMING 2 - -int i_APCI1710_InsnConfigPWM(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InitPWM(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char b_ClockSelection, - unsigned char b_TimingUnit, - unsigned int ul_LowTiming, - unsigned int ul_HighTiming, - unsigned int *pul_RealLowTiming, unsigned int *pul_RealHighTiming); - -int i_APCI1710_GetPWMInitialisation(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char *pb_TimingUnit, - unsigned int *pul_LowTiming, - unsigned int *pul_HighTiming, - unsigned char *pb_StartLevel, - unsigned char *pb_StopMode, - unsigned char *pb_StopLevel, - unsigned char *pb_ExternGate, - unsigned char *pb_InterruptEnable, unsigned char *pb_Enable); - -int i_APCI1710_InsnWritePWM(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_EnablePWM(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, - unsigned char b_StartLevel, - unsigned char b_StopMode, - unsigned char b_StopLevel, unsigned char b_ExternGate, - unsigned char b_InterruptEnable); - -int i_APCI1710_SetNewPWMTiming(struct comedi_device *dev, - unsigned char b_ModulNbr, - unsigned char b_PWM, unsigned char b_TimingUnit, - unsigned int ul_LowTiming, unsigned int ul_HighTiming); - -int i_APCI1710_DisablePWM(struct comedi_device *dev, unsigned char b_ModulNbr, unsigned char b_PWM); - -int i_APCI1710_InsnReadGetPWMStatus(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnBitsReadPWMInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c deleted file mode 100644 index c13b0027492..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.c +++ /dev/null @@ -1,832 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : SSI.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 SSI counter module | - +-----------------------------------------------------------------------+ - | several changes done by S. Weber in 1998 and C. Guinot in 2000 | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ - -#include "APCI1710_Ssi.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitSSI | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SSIProfile, | -| unsigned char_ b_PositionTurnLength, | -| unsigned char_ b_TurnCptLength, | -| unsigned char_ b_PCIInputClock, | -| ULONG_ ul_SSIOutputClock, | -| unsigned char_ b_SSICountingMode) | -+----------------------------------------------------------------------------+ -| Task : Configure the SSI operating mode from selected module | -| (b_ModulNbr). You must calling this function be for you| -| call any other function witch access of SSI. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_SSIProfile : Selection from SSI | -| profile length (2 to 32).| -| unsigned char_ b_PositionTurnLength : Selection from SSI | -| position data length | -| (1 to 31). | -| unsigned char_ b_TurnCptLength : Selection from SSI turn | -| counter data length | -| (1 to 31). | -| unsigned char b_PCIInputClock : Selection from PCI bus | -| clock | -| - APCI1710_30MHZ : | -| The PC have a PCI bus | -| clock from 30 MHz | -| - APCI1710_33MHZ : | -| The PC have a PCI bus | -| clock from 33 MHz | -| ULONG_ ul_SSIOutputClock : Selection from SSI output| -| clock. | -| From 229 to 5 000 000 Hz| -| for 30 MHz selection. | -| From 252 to 5 000 000 Hz| -| for 33 MHz selection. | -| unsigned char b_SSICountingMode : SSI counting mode | -| selection | -| - APCI1710_BINARY_MODE : | -| Binary counting mode. | -| - APCI1710_GRAY_MODE : | -| Gray counting mode. - - b_ModulNbr = CR_AREF(insn->chanspec); - b_SSIProfile = (unsigned char) data[0]; - b_PositionTurnLength= (unsigned char) data[1]; - b_TurnCptLength = (unsigned char) data[2]; - b_PCIInputClock = (unsigned char) data[3]; - ul_SSIOutputClock = (unsigned int) data[4]; - b_SSICountingMode = (unsigned char) data[5]; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a SSI module | -| -4: The selected SSI profile length is wrong | -| -5: The selected SSI position data length is wrong | -| -6: The selected SSI turn counter data length is wrong | -| -7: The selected PCI input clock is wrong | -| -8: The selected SSI output clock is wrong | -| -9: The selected SSI counting mode parameter is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int ui_TimerValue; - unsigned char b_ModulNbr, b_SSIProfile, b_PositionTurnLength, b_TurnCptLength, - b_PCIInputClock, b_SSICountingMode; - unsigned int ul_SSIOutputClock; - - b_ModulNbr = CR_AREF(insn->chanspec); - b_SSIProfile = (unsigned char) data[0]; - b_PositionTurnLength = (unsigned char) data[1]; - b_TurnCptLength = (unsigned char) data[2]; - b_PCIInputClock = (unsigned char) data[3]; - ul_SSIOutputClock = (unsigned int) data[4]; - b_SSICountingMode = (unsigned char) data[5]; - - i_ReturnValue = insn->n; - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if SSI counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { - /*******************************/ - /* Test the SSI profile length */ - /*******************************/ - - /* CG 22/03/00 b_SSIProfile >= 2 anstatt b_SSIProfile > 2 */ - if (b_SSIProfile >= 2 && b_SSIProfile < 33) { - /*************************************/ - /* Test the SSI position data length */ - /*************************************/ - - if (b_PositionTurnLength > 0 - && b_PositionTurnLength < 32) { - /*****************************************/ - /* Test the SSI turn counter data length */ - /*****************************************/ - - if (b_TurnCptLength > 0 - && b_TurnCptLength < 32) { - /***************************/ - /* Test the profile length */ - /***************************/ - - if ((b_TurnCptLength + - b_PositionTurnLength) - <= b_SSIProfile) { - /****************************/ - /* Test the PCI input clock */ - /****************************/ - - if (b_PCIInputClock == - APCI1710_30MHZ - || - b_PCIInputClock - == - APCI1710_33MHZ) - { - /*************************/ - /* Test the output clock */ - /*************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ && (ul_SSIOutputClock > 228 && ul_SSIOutputClock <= 5000000UL)) || (b_PCIInputClock == APCI1710_33MHZ && (ul_SSIOutputClock > 251 && ul_SSIOutputClock <= 5000000UL))) { - if (b_SSICountingMode == APCI1710_BINARY_MODE || b_SSICountingMode == APCI1710_GRAY_MODE) { - /**********************/ - /* Save configuration */ - /**********************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile - = - b_SSIProfile; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength - = - b_PositionTurnLength; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_TurnCptLength - = - b_TurnCptLength; - - /*********************************/ - /* Initialise the profile length */ - /*********************************/ - - if (b_SSICountingMode == APCI1710_BINARY_MODE) { - - outl(b_SSIProfile + 1, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr)); - } else { - - outl(b_SSIProfile, devpriv->s_BoardInfos.ui_Address + 4 + (64 * b_ModulNbr)); - } - - /******************************/ - /* Calculate the output clock */ - /******************************/ - - ui_TimerValue - = - (unsigned int) - ( - ((unsigned int) (b_PCIInputClock) * 500000UL) / ul_SSIOutputClock); - - /************************/ - /* Initialise the timer */ - /************************/ - - outl(ui_TimerValue, devpriv->s_BoardInfos.ui_Address + (64 * b_ModulNbr)); - - /********************************/ - /* Initialise the counting mode */ - /********************************/ - - outl(7 * b_SSICountingMode, devpriv->s_BoardInfos.ui_Address + 12 + (64 * b_ModulNbr)); - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIInit - = - 1; - } else { - /*****************************************************/ - /* The selected SSI counting mode parameter is wrong */ - /*****************************************************/ - - DPRINTK("The selected SSI counting mode parameter is wrong\n"); - i_ReturnValue - = - -9; - } - } else { - /******************************************/ - /* The selected SSI output clock is wrong */ - /******************************************/ - - DPRINTK("The selected SSI output clock is wrong\n"); - i_ReturnValue - = - -8; - } - } else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = - -7; - } - } else { - /********************************************/ - /* The selected SSI profile length is wrong */ - /********************************************/ - - DPRINTK("The selected SSI profile length is wrong\n"); - i_ReturnValue = -4; - } - } else { - /******************************************************/ - /* The selected SSI turn counter data length is wrong */ - /******************************************************/ - - DPRINTK("The selected SSI turn counter data length is wrong\n"); - i_ReturnValue = -6; - } - } else { - /**************************************************/ - /* The selected SSI position data length is wrong */ - /**************************************************/ - - DPRINTK("The selected SSI position data length is wrong\n"); - i_ReturnValue = -5; - } - } else { - /********************************************/ - /* The selected SSI profile length is wrong */ - /********************************************/ - - DPRINTK("The selected SSI profile length is wrong\n"); - i_ReturnValue = -4; - } - } else { - /**********************************/ - /* The module is not a SSI module */ - /**********************************/ - - DPRINTK("The module is not a SSI module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_Read1SSIValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SelectedSSI, | -| PULONG_ pul_Position, | -| PULONG_ pul_TurnCpt) - int i_APCI1710_ReadSSIValue(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : - - - Read the selected SSI counter (b_SelectedSSI) from | -| selected module (b_ModulNbr). - or Read all SSI counter (b_SelectedSSI) from | -| selected module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -| unsigned char_ b_SelectedSSI : Selection from SSI | -| counter (0 to 2) - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); (in case of single ssi) - b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); -| -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_Position : SSI position in the turn | -| PULONG_ pul_TurnCpt : Number of turns - -pul_Position = (unsigned int *) &data[0]; - pul_TurnCpt = (unsigned int *) &data[1]; | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a SSI module | -| -4: SSI not initialised see function | -| "i_APCI1710_InitSSI" | -| -5: The selected SSI is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned char b_Cpt; - unsigned char b_Length; - unsigned char b_Schift; - unsigned char b_SSICpt; - unsigned int dw_And; - unsigned int dw_And1; - unsigned int dw_And2; - unsigned int dw_StatusReg; - unsigned int dw_CounterValue; - unsigned char b_ModulNbr; - unsigned char b_SelectedSSI; - unsigned char b_ReadType; - unsigned int *pul_Position; - unsigned int *pul_TurnCpt; - unsigned int *pul_Position1; - unsigned int *pul_TurnCpt1; - - i_ReturnValue = insn->n; - pul_Position1 = (unsigned int *) &data[0]; -/* For Read1 */ - pul_TurnCpt1 = (unsigned int *) &data[1]; -/* For Read all */ - pul_Position = (unsigned int *) &data[0]; /* 0-2 */ - pul_TurnCpt = (unsigned int *) &data[3]; /* 3-5 */ - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_SelectedSSI = (unsigned char) CR_CHAN(insn->chanspec); - b_ReadType = (unsigned char) CR_RANGE(insn->chanspec); - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if SSI counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { - /***************************/ - /* Test if SSI initialised */ - /***************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_SSICounterInfo.b_SSIInit == 1) { - - switch (b_ReadType) { - - case APCI1710_SSI_READ1VALUE: - /****************************************/ - /* Test the selected SSI counter number */ - /****************************************/ - - if (b_SelectedSSI < 3) { - /************************/ - /* Start the conversion */ - /************************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 8 + - (64 * b_ModulNbr)); - - do { - /*******************/ - /* Read the status */ - /*******************/ - - dw_StatusReg = - inl(devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - } while ((dw_StatusReg & 0x1) - != 0); - - /******************************/ - /* Read the SSI counter value */ - /******************************/ - - dw_CounterValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 4 + - (b_SelectedSSI * 4) + - (64 * b_ModulNbr)); - - b_Length = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile / 2; - - if ((b_Length * 2) != - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile) { - b_Length++; - } - - b_Schift = - b_Length - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength; - - *pul_Position1 = - dw_CounterValue >> - b_Schift; - - dw_And = 1; - - for (b_Cpt = 0; - b_Cpt < - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength; - b_Cpt++) { - dw_And = dw_And * 2; - } - - *pul_Position1 = - *pul_Position1 & - ((dw_And) - 1); - - *pul_TurnCpt1 = - dw_CounterValue >> - b_Length; - - dw_And = 1; - - for (b_Cpt = 0; - b_Cpt < - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_TurnCptLength; - b_Cpt++) { - dw_And = dw_And * 2; - } - - *pul_TurnCpt1 = - *pul_TurnCpt1 & - ((dw_And) - 1); - } else { - /*****************************/ - /* The selected SSI is wrong */ - /*****************************/ - - DPRINTK("The selected SSI is wrong\n"); - i_ReturnValue = -5; - } - break; - - case APCI1710_SSI_READALLVALUE: - dw_And1 = 1; - - for (b_Cpt = 0; - b_Cpt < - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength; b_Cpt++) { - dw_And1 = dw_And1 * 2; - } - - dw_And2 = 1; - - for (b_Cpt = 0; - b_Cpt < - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_SSICounterInfo. - b_TurnCptLength; b_Cpt++) { - dw_And2 = dw_And2 * 2; - } - - /************************/ - /* Start the conversion */ - /************************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 8 + - (64 * b_ModulNbr)); - - do { - /*******************/ - /* Read the status */ - /*******************/ - - dw_StatusReg = - inl(devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - } while ((dw_StatusReg & 0x1) != 0); - - for (b_SSICpt = 0; b_SSICpt < 3; - b_SSICpt++) { - /******************************/ - /* Read the SSI counter value */ - /******************************/ - - dw_CounterValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 4 + - (b_SSICpt * 4) + - (64 * b_ModulNbr)); - - b_Length = - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile / 2; - - if ((b_Length * 2) != - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_SSIProfile) { - b_Length++; - } - - b_Schift = - b_Length - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_SSICounterInfo. - b_PositionTurnLength; - - pul_Position[b_SSICpt] = - dw_CounterValue >> - b_Schift; - pul_Position[b_SSICpt] = - pul_Position[b_SSICpt] & - ((dw_And1) - 1); - - pul_TurnCpt[b_SSICpt] = - dw_CounterValue >> - b_Length; - pul_TurnCpt[b_SSICpt] = - pul_TurnCpt[b_SSICpt] & - ((dw_And2) - 1); - } - break; - - default: - printk("Read Type Inputs Wrong\n"); - - } /* switch ending */ - - } else { - /***********************/ - /* SSI not initialised */ - /***********************/ - - DPRINTK("SSI not initialised\n"); - i_ReturnValue = -4; - } - } else { - /**********************************/ - /* The module is not a SSI module */ - /**********************************/ - - DPRINTK("The module is not a SSI module\n"); - i_ReturnValue = -3; - - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadSSI1DigitalInput | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_InputChannel, | -| unsigned char *_ pb_ChannelStatus) | -+----------------------------------------------------------------------------+ -| Task : - (0) Set the digital output from selected SSI moule | -| (b_ModuleNbr) ON - (1) Set the digital output from selected SSI moule | -| (b_ModuleNbr) OFF - (2)Read the status from selected SSI digital input | -| (b_InputChannel) - (3)Read the status from all SSI digital inputs from | -| selected SSI module (b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr CR_AREF : Module number to | -| configure (0 to 3) | -| unsigned char_ b_InputChannel CR_CHAN : Selection from digital | -| data[0] which IOTYPE input ( 0 to 2) | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_ChannelStatus : Digital input channel | -| data[0] status | -| 0 : Channle is not active| -| 1 : Channle is active | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a SSI module | -| -4: The selected SSI digital input is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr; - unsigned char b_InputChannel; - unsigned char *pb_ChannelStatus; - unsigned char *pb_InputStatus; - unsigned char b_IOType; - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_IOType = (unsigned char) data[0]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if SSI counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_SSI_COUNTER) { - switch (b_IOType) { - case APCI1710_SSI_SET_CHANNELON: - /*****************************/ - /* Set the digital output ON */ - /*****************************/ - - outl(1, devpriv->s_BoardInfos.ui_Address + 16 + - (64 * b_ModulNbr)); - break; - - case APCI1710_SSI_SET_CHANNELOFF: - /******************************/ - /* Set the digital output OFF */ - /******************************/ - - outl(0, devpriv->s_BoardInfos.ui_Address + 16 + - (64 * b_ModulNbr)); - break; - - case APCI1710_SSI_READ_1CHANNEL: - /******************************************/ - /* Test the digital imnput channel number */ - /******************************************/ - - b_InputChannel = (unsigned char) CR_CHAN(insn->chanspec); - pb_ChannelStatus = (unsigned char *) &data[0]; - - if (b_InputChannel <= 2) { - /**************************/ - /* Read all digital input */ - /**************************/ - - dw_StatusReg = - inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - *pb_ChannelStatus = - (unsigned char) (((~dw_StatusReg) >> (4 + - b_InputChannel)) - & 1); - } else { - /********************************/ - /* Selected digital input error */ - /********************************/ - - DPRINTK("Selected digital input error\n"); - i_ReturnValue = -4; - } - break; - - case APCI1710_SSI_READ_ALLCHANNEL: - /**************************/ - /* Read all digital input */ - /**************************/ - pb_InputStatus = (unsigned char *) &data[0]; - - dw_StatusReg = - inl(devpriv->s_BoardInfos.ui_Address + - (64 * b_ModulNbr)); - *pb_InputStatus = - (unsigned char) (((~dw_StatusReg) >> 4) & 7); - break; - - default: - printk("IO type wrong\n"); - - } /* switch end */ - } else { - /**********************************/ - /* The module is not a SSI module */ - /**********************************/ - - DPRINTK("The module is not a SSI module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h deleted file mode 100644 index ef4d88789d5..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ssi.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_BINARY_MODE 0x1 -#define APCI1710_GRAY_MODE 0x0 - -#define APCI1710_SSI_READ1VALUE 1 -#define APCI1710_SSI_READALLVALUE 2 - -#define APCI1710_SSI_SET_CHANNELON 0 -#define APCI1710_SSI_SET_CHANNELOFF 1 -#define APCI1710_SSI_READ_1CHANNEL 2 -#define APCI1710_SSI_READ_ALLCHANNEL 3 - -/* - * SSI INISIALISATION FUNCTION - */ -int i_APCI1710_InsnConfigInitSSI(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnReadSSIValue(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnBitsSSIDigitalIO(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c deleted file mode 100644 index 0e6affd9596..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.c +++ /dev/null @@ -1,2049 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : TOR.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 tor counter module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 27/01/99 | S. Weber | 40 MHz implementation | - +-----------------------------------------------------------------------+ - | 28/04/00 | S. Weber | Simple,double and quadruple mode implementation| - | | | Extern clock implementation | - +-----------------------------------------------------------------------+ - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ - -#include "APCI1710_Tor.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitTorCounter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter, | -| unsigned char_ b_PCIInputClock, | -| unsigned char_ b_TimingUnit, | -| ULONG_ ul_TimingInterval, | -| PULONG_ pul_RealTimingInterval) | -+----------------------------------------------------------------------------+ -| Task : Configure the selected tor counter (b_TorCounter) | -| from selected module (b_ModulNbr). | -| The ul_TimingInterval and ul_TimingUnit determine the | -| timing base for the measurement. | -| The pul_RealTimingInterval return the real timing | -| value. You must calling this function be for you call | -| any other function witch access of the tor counter. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| - CR_AREF unsigned char_ b_ModulNbr : Module number to configure | -| (0 to 3) | -| data[0] unsigned char_ b_TorCounter : Tor counter selection | -| (0 or 1). | -| data[1] unsigned char_ b_PCIInputClock : Selection from PCI bus clock| -| - APCI1710_30MHZ : | -| The PC have a PCI bus | -| clock from 30 MHz | -| - APCI1710_33MHZ : | -| The PC have a PCI bus | -| clock from 33 MHz | -| - APCI1710_40MHZ | -| The APCI-1710 have a | -| integrated 40Mhz | -| quartz. | -| - APCI1710_GATE_INPUT | -| Used the gate input for | -| the base clock. If you | -| have selected this option,| -| than it is not possibl to | -| used the gate input for | -| enabled the acquisition | -| data[2] unsigned char_ b_TimingUnit : Base timing unit (0 to 4) | -| 0 : ns | -| 1 : µs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| data[3] ULONG_ ul_TimingInterval : Base timing value. | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_RealTimingInterval : Real base timing | -| data[0] value. | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: The selected PCI input clock is wrong | -| -6: Timing unit selection is wrong | -| -7: Base timing selection is wrong | -| -8: You can not used the 40MHz clock selection wich | -| this board | -| -9: You can not used the 40MHz clock selection wich | -| this TOR version | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int ul_TimerValue = 0; - unsigned int dw_Command; - double d_RealTimingInterval = 0; - unsigned char b_ModulNbr; - unsigned char b_TorCounter; - unsigned char b_PCIInputClock; - unsigned char b_TimingUnit; - unsigned int ul_TimingInterval; - unsigned int ul_RealTimingInterval = 0; - - i_ReturnValue = insn->n; - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - - b_TorCounter = (unsigned char) data[0]; - b_PCIInputClock = (unsigned char) data[1]; - b_TimingUnit = (unsigned char) data[2]; - ul_TimingInterval = (unsigned int) data[3]; - printk("INPUT clock %d\n", b_PCIInputClock); - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - /**********************************/ - /* Test the tor counter selection */ - /**********************************/ - - if (b_TorCounter <= 1) { - /**************************/ - /* Test the PCI bus clock */ - /**************************/ - - if ((b_PCIInputClock == APCI1710_30MHZ) || - (b_PCIInputClock == APCI1710_33MHZ) || - (b_PCIInputClock == APCI1710_40MHZ) || - (b_PCIInputClock == - APCI1710_GATE_INPUT)) { - /************************/ - /* Test the timing unit */ - /************************/ - - if ((b_TimingUnit <= 4) - || (b_PCIInputClock == - APCI1710_GATE_INPUT)) { - /**********************************/ - /* Test the base timing selection */ - /**********************************/ - - if (((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 133) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230650UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571230UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 571UL)) || ((b_PCIInputClock == APCI1710_30MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 9UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 121) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691043UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 519691UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 520UL)) || ((b_PCIInputClock == APCI1710_33MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 8UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 0) && (ul_TimingInterval >= 100) && (ul_TimingInterval <= 0xFFFFFFFFUL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 1) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496729UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 2) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429496UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 3) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 429UL)) || ((b_PCIInputClock == APCI1710_40MHZ) && (b_TimingUnit == 4) && (ul_TimingInterval >= 1) && (ul_TimingInterval <= 7UL)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && (ul_TimingInterval >= 2))) { - /**************************/ - /* Test the board version */ - /**************************/ - - if (((b_PCIInputClock == APCI1710_40MHZ) && (devpriv->s_BoardInfos.b_BoardVersion > 0)) || (b_PCIInputClock != APCI1710_40MHZ)) { - /************************/ - /* Test the TOR version */ - /************************/ - - if (((b_PCIInputClock == APCI1710_40MHZ) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3131)) || ((b_PCIInputClock == APCI1710_GATE_INPUT) && ((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3132)) || (b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) { - /*********************************/ - /* Test if not extern clock used */ - /*********************************/ - - if (b_PCIInputClock != APCI1710_GATE_INPUT) { - fpu_begin - (); - /****************************************/ - /* Calculate the timer 0 division fator */ - /****************************************/ - - switch (b_TimingUnit) { - /******/ - /* ns */ - /******/ - - case 0: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.00025 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.00025 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.00025 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (0.00025 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.00025 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* æs */ - /******/ - - case 1: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (0.25 * b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (0.25 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (0.25 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - ( - (double) - 0.25 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (0.25 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* ms */ - /******/ - - case 2: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - ul_TimingInterval - * - (250.0 - * - b_PCIInputClock); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (250.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (250.0 * (double)b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (250.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (250.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - - /*****/ - /* s */ - /*****/ - - case 3: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - (ul_TimingInterval - * - (250000.0 - * - b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)ul_TimingInterval * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (250000.0 - * - (double) - b_PCIInputClock)); - d_RealTimingInterval - = - (double) - ul_TimerValue - / - (250000.0 - * - (double) - b_PCIInputClock); - - if ((double)((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - - /******/ - /* mn */ - /******/ - - case 4: - - /******************/ - /* Timer 0 factor */ - /******************/ - - ul_TimerValue - = - (unsigned int) - ( - (ul_TimingInterval - * - 60) - * - (250000.0 - * - b_PCIInputClock)); - - /*******************/ - /* Round the value */ - /*******************/ - - if ((double)((double)(ul_TimingInterval * 60.0) * (250000.0 * (double)b_PCIInputClock)) >= ((double)((double)ul_TimerValue + 0.5))) { - ul_TimerValue - = - ul_TimerValue - + - 1; - } - - /*****************************/ - /* Calculate the real timing */ - /*****************************/ - - ul_RealTimingInterval - = - (unsigned int) - (ul_TimerValue - / - (250000.0 - * - (double) - b_PCIInputClock)) - / - 60; - d_RealTimingInterval - = - ( - (double) - ul_TimerValue - / - (250000.0 - * - (double) - b_PCIInputClock)) - / - 60.0; - - if ((double)(((double)ul_TimerValue / (250000.0 * (double)b_PCIInputClock)) / 60.0) >= (double)((double)ul_RealTimingInterval + 0.5)) { - ul_RealTimingInterval - = - ul_RealTimingInterval - + - 1; - } - - ul_TimingInterval - = - ul_TimingInterval - - - 1; - ul_TimerValue - = - ul_TimerValue - - - 2; - - if (b_PCIInputClock != APCI1710_40MHZ) { - ul_TimerValue - = - (unsigned int) - ( - (double) - (ul_TimerValue) - * - 1.007752288); - } - - break; - } - - fpu_end(); - } /* if (b_PCIInputClock != APCI1710_GATE_INPUT) */ - else { - /*************************************************************/ - /* 2 Clock used for the overflow and the reload from counter */ - /*************************************************************/ - - ul_TimerValue - = - ul_TimingInterval - - - 2; - } /* if (b_PCIInputClock != APCI1710_GATE_INPUT) */ - - /****************************/ - /* Save the PCI input clock */ - /****************************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - b_PCIInputClock - = - b_PCIInputClock; - - /************************/ - /* Save the timing unit */ - /************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - b_TimingUnit - = - b_TimingUnit; - - /************************/ - /* Save the base timing */ - /************************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - d_TimingInterval - = - d_RealTimingInterval; - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - ul_RealTimingInterval - = - ul_RealTimingInterval; - - /*******************/ - /* Get the command */ - /*******************/ - - dw_Command - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 4 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - dw_Command - = - (dw_Command - >> - 4) - & - 0xF; - - /******************/ - /* Test if 40 MHz */ - /******************/ - - if (b_PCIInputClock == APCI1710_40MHZ) { - /****************************/ - /* Set the 40 MHz selection */ - /****************************/ - - dw_Command - = - dw_Command - | - 0x10; - } - - /*****************************/ - /* Test if extern clock used */ - /*****************************/ - - if (b_PCIInputClock == APCI1710_GATE_INPUT) { - /****************************/ - /* Set the 40 MHz selection */ - /****************************/ - - dw_Command - = - dw_Command - | - 0x20; - } - - /*************************/ - /* Write the new command */ - /*************************/ - - outl(dw_Command, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /*******************/ - /* Disable the tor */ - /*******************/ - - outl(0, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - /*************************/ - /* Set the timer 1 value */ - /*************************/ - - outl(ul_TimerValue, devpriv->s_BoardInfos.ui_Address + 0 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /*********************/ - /* Tor counter init. */ - /*********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - b_TorCounterInit - = - 1; - } else { - /***********************************************/ - /* TOR version error for 40MHz clock selection */ - /***********************************************/ - - DPRINTK("TOR version error for 40MHz clock selection\n"); - i_ReturnValue - = - -9; - } - } else { - /**************************************************************/ - /* You can not used the 40MHz clock selection wich this board */ - /**************************************************************/ - - DPRINTK("You can not used the 40MHz clock selection wich this board\n"); - i_ReturnValue = - -8; - } - } else { - /**********************************/ - /* Base timing selection is wrong */ - /**********************************/ - - DPRINTK("Base timing selection is wrong\n"); - i_ReturnValue = -7; - } - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - else { - /**********************************/ - /* Timing unit selection is wrong */ - /**********************************/ - - DPRINTK("Timing unit selection is wrong\n"); - i_ReturnValue = -6; - } /* if ((b_TimingUnit >= 0) && (b_TimingUnit <= 4)) */ - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ - else { - /*****************************************/ - /* The selected PCI input clock is wrong */ - /*****************************************/ - - DPRINTK("The selected PCI input clock is wrong\n"); - i_ReturnValue = -5; - } /* if ((b_PCIInputClock == APCI1710_30MHZ) || (b_PCIInputClock == APCI1710_33MHZ)) */ - } /* if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */ - else { - /**********************************/ - /* Tor Counter selection is wrong */ - /**********************************/ - - DPRINTK("Tor Counter selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_TorCounterMode >= 0 && b_TorCounterMode <= 7) */ - } else { - /******************************************/ - /* The module is not a tor counter module */ - /******************************************/ - - DPRINTK("The module is not a tor counter module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - data[0] = (unsigned int) ul_RealTimingInterval; - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_EnableTorCounter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter, | -| unsigned char_ b_InputMode, | -| unsigned char_ b_ExternGate, | -| unsigned char_ b_CycleMode, | -| unsigned char_ b_InterruptEnable) | -+----------------------------------------------------------------------------+ -| Task : Enable the tor counter (b_TorCounter) from selected | -| module (b_ModulNbr). You must calling the | -| "i_APCI1710_InitTorCounter" function be for you call | -| this function. | -| If you enable the tor counter interrupt, the | -| tor counter generate a interrupt after the timing cycle| -| See function "i_APCI1710_SetBoardIntRoutineX" and the | -| Interrupt mask description chapter from this manual. | -| The b_CycleMode parameter determine if you will | -| measured a single or more cycle. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). | -| unsigned char_ b_InputMode : Input signal level selection | -| 0 : Tor count each low level | -| 1 : Tor count each high level| -| unsigned char_ b_ExternGate : Extern gate action selection | -| 0 : Extern gate signal not | -| used | -| 1 : Extern gate signal used. | -| If you selected the | -| single mode, each high | -| level signal start the | -| counter. | -| If you selected the | -| continuous mode, the | -| first high level signal | -| start the tor counter | -| | -| APCI1710_TOR_QUADRUPLE _MODE : | -| In the quadruple mode, the edge| -| analysis circuit generates a | -| counting pulse from each edge | -| of 2 signals which are phase | -| shifted in relation to each | -| other. | -| The gate input is used for the | -| signal B | -| | -| APCI1710_TOR_DOUBLE_MODE: | -| Functions in the same way as | -| the quadruple mode, except that| -| only two of the four edges are | -| analysed per period. | -| The gate input is used for the | -| signal B | -| | -| APCI1710_TOR_SIMPLE_MODE: | -| Functions in the same way as | -| the quadruple mode, except that| -| only one of the four edges is | -| analysed per period. | -| The gate input is used for the | -| signal B | -| | -| unsigned char_ b_CycleMode : Selected the tor counter | -| acquisition mode | -| unsigned char_ b_InterruptEnable : Enable or disable the | -| tor counter interrupt. | -| APCI1710_ENABLE: | -| Enable the tor counter | -| interrupt | -| APCI1710_DISABLE: | -| Disable the tor counter | -| interrupt | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: Tor counter not initialised see function | -| "i_APCI1710_InitTorCounter" | -| -6: Tor input signal selection is wrong | -| -7: Extern gate signal mode is wrong | -| -8: Tor counter acquisition mode cycle is wrong | -| -9: Interrupt parameter is wrong | -| -10:Interrupt function not initialised. | -| See function "i_APCI1710_SetBoardIntRoutineX" | -+----------------------------------------------------------------------------+ -*/ -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_DisableTorCounter | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter) | -+----------------------------------------------------------------------------+ -| Task : Disable the tor counter (b_TorCounter) from selected | -| module (b_ModulNbr). If you disable the tor counter | -| after a start cycle occur and you restart the tor | -| counter witch the " i_APCI1710_EnableTorCounter" | -| function, the status register is cleared | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: Tor counter not initialised see function | -| "i_APCI1710_InitTorCounter" | -| -6: Tor counter not enabled see function | -| "i_APCI1710_EnableTorCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_DummyRead; - unsigned int dw_ConfigReg; - unsigned char b_ModulNbr, b_Action; - unsigned char b_TorCounter; - unsigned char b_InputMode; - unsigned char b_ExternGate; - unsigned char b_CycleMode; - unsigned char b_InterruptEnable; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_Action = (unsigned char) data[0]; /* enable or disable */ - b_TorCounter = (unsigned char) data[1]; - b_InputMode = (unsigned char) data[2]; - b_ExternGate = (unsigned char) data[3]; - b_CycleMode = (unsigned char) data[4]; - b_InterruptEnable = (unsigned char) data[5]; - i_ReturnValue = insn->n; - devpriv->tsk_Current = current; /* Save the current process task structure */ - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - /**********************************/ - /* Test the tor counter selection */ - /**********************************/ - - if (b_TorCounter <= 1) { - switch (b_Action) /* Enable or Disable */ - { - case APCI1710_ENABLE: - /***********************************/ - /* Test if tor counter initialised */ - /***********************************/ - - dw_Status = - inl(devpriv->s_BoardInfos. - ui_Address + 8 + - (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - /******************************/ - /* Test the input signal mode */ - /******************************/ - - if (b_InputMode == 0 || - b_InputMode == 1 || - b_InputMode == - APCI1710_TOR_SIMPLE_MODE - || b_InputMode == - APCI1710_TOR_DOUBLE_MODE - || b_InputMode == - APCI1710_TOR_QUADRUPLE_MODE) - { - /************************************/ - /* Test the extern gate signal mode */ - /************************************/ - - if (b_ExternGate == 0 - || b_ExternGate - == 1 - || b_InputMode > - 1) { - /*********************************/ - /* Test the cycle mode parameter */ - /*********************************/ - - if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) { - /***************************/ - /* Test the interrupt flag */ - /***************************/ - - if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) { - - /***************************/ - /* Save the interrupt mode */ - /***************************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - b_InterruptEnable - = - b_InterruptEnable; - - /*******************/ - /* Get the command */ - /*******************/ - - dw_ConfigReg - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 4 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - dw_ConfigReg - = - (dw_ConfigReg - >> - 4) - & - 0x30; - - /********************************/ - /* Test if not direct mode used */ - /********************************/ - - if (b_InputMode > 1) { - /*******************************/ - /* Extern gate can not be used */ - /*******************************/ - - b_ExternGate - = - 0; - - /*******************************************/ - /* Enable the extern gate for the Signal B */ - /*******************************************/ - - dw_ConfigReg - = - dw_ConfigReg - | - 0x40; - - /***********************/ - /* Test if simple mode */ - /***********************/ - - if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) { - /**************************/ - /* Enable the sinple mode */ - /**************************/ - - dw_ConfigReg - = - dw_ConfigReg - | - 0x780; - - } /* if (b_InputMode == APCI1710_TOR_SIMPLE_MODE) */ - - /***********************/ - /* Test if double mode */ - /***********************/ - - if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) { - /**************************/ - /* Enable the double mode */ - /**************************/ - - dw_ConfigReg - = - dw_ConfigReg - | - 0x180; - - } /* if (b_InputMode == APCI1710_TOR_DOUBLE_MODE) */ - - b_InputMode - = - 0; - } /* if (b_InputMode > 1) */ - - /*******************/ - /* Set the command */ - /*******************/ - - dw_ConfigReg - = - dw_ConfigReg - | - b_CycleMode - | - (b_InterruptEnable - * - 2) - | - (b_InputMode - * - 4) - | - (b_ExternGate - * - 8); - - /*****************************/ - /* Clear the status register */ - /*****************************/ - - dw_DummyRead - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 0 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /***************************************/ - /* Clear the interrupt status register */ - /***************************************/ - - dw_DummyRead - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 12 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /********************/ - /* Set the commando */ - /********************/ - - outl(dw_ConfigReg, devpriv->s_BoardInfos.ui_Address + 4 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - - /****************/ - /* Set the gate */ - /****************/ - - outl(1, devpriv->s_BoardInfos.ui_Address + 8 + (16 * b_TorCounter) + (64 * b_ModulNbr)); - - } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ - else { - /********************************/ - /* Interrupt parameter is wrong */ - /********************************/ - - DPRINTK("Interrupt parameter is wrong\n"); - i_ReturnValue - = - -9; - } /* if ((b_InterruptEnable == APCI1710_ENABLE) || (b_InterruptEnable == APCI1710_DISABLE)) */ - } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ - else { - /***********************************************/ - /* Tor counter acquisition mode cycle is wrong */ - /***********************************************/ - - DPRINTK("Tor counter acquisition mode cycle is wrong\n"); - i_ReturnValue - = - -8; - } /* if ((b_CycleMode == APCI1710_SINGLE) || (b_CycleMode == APCI1710_CONTINUOUS)) */ - } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ - else { - /***********************************/ - /* Extern gate input mode is wrong */ - /***********************************/ - - DPRINTK("Extern gate input mode is wrong\n"); - i_ReturnValue = - -7; - } /* if (b_ExternGate >= 0 && b_ExternGate <= 1) */ - } /* if (b_InputMode >= 0 && b_InputMode <= 1) */ - else { - /***************************************/ - /* Tor input signal selection is wrong */ - /***************************************/ - - DPRINTK("Tor input signal selection is wrong\n"); - i_ReturnValue = -6; - } - } else { - /*******************************/ - /* Tor counter not initialised */ - /*******************************/ - - DPRINTK("Tor counter not initialised\n"); - i_ReturnValue = -5; - } - break; - - case APCI1710_DISABLE: - /***********************************/ - /* Test if tor counter initialised */ - /***********************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 8 + - (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (dw_Status & 0x10) { - /***************************/ - /* Test if counter enabled */ - /***************************/ - - if (dw_Status & 0x1) { - /****************************/ - /* Clear the interrupt mode */ - /****************************/ - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo - [b_TorCounter]. - b_InterruptEnable - = - APCI1710_DISABLE; - - /******************/ - /* Clear the gate */ - /******************/ - - outl(0, devpriv-> - s_BoardInfos. - ui_Address + 8 + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - } /* if (dw_Status & 0x1) */ - else { - /***************************/ - /* Tor counter not enabled */ - /***************************/ - - DPRINTK("Tor counter not enabled \n"); - i_ReturnValue = -6; - } /* if (dw_Status & 0x1) */ - } /* if (dw_Status & 0x10) */ - else { - /*******************************/ - /* Tor counter not initialised */ - /*******************************/ - - DPRINTK("Tor counter not initialised\n"); - i_ReturnValue = -5; - } /* // if (dw_Status & 0x10) */ - - } /* switch */ - } /* if (b_TorCounter <= 1) */ - else { - /**********************************/ - /* Tor counter selection is wrong */ - /**********************************/ - - DPRINTK("Tor counter selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_TorCounter <= 1) */ - } else { - /******************************************/ - /* The module is not a tor counter module */ - /******************************************/ - - DPRINTK("The module is not a tor counter module \n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error \n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_GetTorCounterInitialisation | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter, | -| unsigned char *_ pb_TimingUnit, | -| PULONG_ pul_TimingInterval, | -| unsigned char *_ pb_InputMode, | -| unsigned char *_ pb_ExternGate, | -| unsigned char *_ pb_CycleMode, | -| unsigned char *_ pb_Enable, | -| unsigned char *_ pb_InterruptEnable)| -+----------------------------------------------------------------------------+ -| Task : Enable the tor counter (b_TorCounter) from selected | -| module (b_ModulNbr). You must calling the | -| "i_APCI1710_InitTorCounter" function be for you call | -| this function. | -| If you enable the tor counter interrupt, the | -| tor counter generate a interrupt after the timing cycle| -| See function "i_APCI1710_SetBoardIntRoutineX" and the | -| Interrupt mask description chapter from this manual. | -| The b_CycleMode parameter determine if you will | -| measured a single or more cycle. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_TorCounter : Tor counter selection (0 or 1) - - b_ModulNbr = CR_AREF(insn->chanspec); - b_TorCounter = CR_CHAN(insn->chanspec); -. | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TimingUnit : Base timing unit (0 to 4) | -| 0 : ns | -| 1 : µs | -| 2 : ms | -| 3 : s | -| 4 : mn | -| PULONG_ pul_TimingInterval : Base timing value. | -| unsigned char *_ pb_InputMode : Input signal level | -| selection | -| 0 : Tor count each low level | -| 1 : Tor count each high level| -| unsigned char *_ pb_ExternGate : Extern gate action | -| selection | -| 0 : Extern gate signal not | -| used | -| 1 : Extern gate signal used| -| unsigned char *_ pb_CycleMode : Tor counter acquisition | -| mode | -| unsigned char *_ pb_Enable : Indicate if the tor counter| -| is enabled or no | -| 0 : Tor counter disabled | -| 1 : Tor counter enabled | -| unsigned char *_ pb_InterruptEnable : Enable or disable the | -| tor counter interrupt. | -| APCI1710_ENABLE: | -| Enable the tor counter | -| interrupt | -| APCI1710_DISABLE: | -| Disable the tor counter | -| interrupt - pb_TimingUnit = (unsigned char *) &data[0]; - pul_TimingInterval = (unsigned int *) &data[1]; - pb_InputMode = (unsigned char *) &data[2]; - pb_ExternGate = (unsigned char *) &data[3]; - pb_CycleMode = (unsigned char *) &data[4]; - pb_Enable = (unsigned char *) &data[5]; - pb_InterruptEnable = (unsigned char *) &data[6]; - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: Tor counter not initialised see function | -| "i_APCI1710_InitTorCounter" | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned char b_ModulNbr; - unsigned char b_TorCounter; - unsigned char *pb_TimingUnit; - unsigned int *pul_TimingInterval; - unsigned char *pb_InputMode; - unsigned char *pb_ExternGate; - unsigned char *pb_CycleMode; - unsigned char *pb_Enable; - unsigned char *pb_InterruptEnable; - - i_ReturnValue = insn->n; - b_ModulNbr = CR_AREF(insn->chanspec); - b_TorCounter = CR_CHAN(insn->chanspec); - - pb_TimingUnit = (unsigned char *) &data[0]; - pul_TimingInterval = (unsigned int *) &data[1]; - pb_InputMode = (unsigned char *) &data[2]; - pb_ExternGate = (unsigned char *) &data[3]; - pb_CycleMode = (unsigned char *) &data[4]; - pb_Enable = (unsigned char *) &data[5]; - pb_InterruptEnable = (unsigned char *) &data[6]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - /**********************************/ - /* Test the tor counter selection */ - /**********************************/ - - if (b_TorCounter <= 1) { - - /***********************************/ - /* Test if tor counter initialised */ - /***********************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - if (dw_Status & 0x10) { - *pb_Enable = dw_Status & 1; - - /********************/ - /* Get the commando */ - /********************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 4 + - (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - *pb_CycleMode = - (unsigned char) ((dw_Status >> 4) & 1); - *pb_InterruptEnable = - (unsigned char) ((dw_Status >> 5) & 1); - - /******************************************************/ - /* Test if extern gate used for clock or for signal B */ - /******************************************************/ - - if (dw_Status & 0x600) { - /*****************************************/ - /* Test if extern gate used for signal B */ - /*****************************************/ - - if (dw_Status & 0x400) { - /***********************/ - /* Test if simple mode */ - /***********************/ - - if ((dw_Status & 0x7800) - == 0x7800) { - *pb_InputMode = - APCI1710_TOR_SIMPLE_MODE; - } - - /***********************/ - /* Test if double mode */ - /***********************/ - - if ((dw_Status & 0x7800) - == 0x1800) { - *pb_InputMode = - APCI1710_TOR_DOUBLE_MODE; - } - - /**************************/ - /* Test if quadruple mode */ - /**************************/ - - if ((dw_Status & 0x7800) - == 0x0000) { - *pb_InputMode = - APCI1710_TOR_QUADRUPLE_MODE; - } - } /* if (dw_Status & 0x400) */ - else { - *pb_InputMode = 1; - } /* // if (dw_Status & 0x400) */ - - /************************/ - /* Extern gate not used */ - /************************/ - - *pb_ExternGate = 0; - } /* if (dw_Status & 0x600) */ - else { - *pb_InputMode = - (unsigned char) ((dw_Status >> 6) - & 1); - *pb_ExternGate = - (unsigned char) ((dw_Status >> 7) - & 1); - } /* if (dw_Status & 0x600) */ - - *pb_TimingUnit = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo[b_TorCounter]. - b_TimingUnit; - - *pul_TimingInterval = - devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TorCounterModuleInfo. - s_TorCounterInfo[b_TorCounter]. - ul_RealTimingInterval; - } else { - /*******************************/ - /* Tor counter not initialised */ - /*******************************/ - - DPRINTK("Tor counter not initialised\n"); - i_ReturnValue = -5; - } - - } /* if (b_TorCounter <= 1) */ - else { - /**********************************/ - /* Tor counter selection is wrong */ - /**********************************/ - - DPRINTK("Tor counter selection is wrong \n"); - i_ReturnValue = -4; - } /* if (b_TorCounter <= 1) */ - } else { - /******************************************/ - /* The module is not a tor counter module */ - /******************************************/ - - DPRINTK("The module is not a tor counter module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadTorCounterValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_TorCounter, | -| unsigned int_ ui_TimeOut, | -| unsigned char *_ pb_TorCounterStatus, | -| PULONG_ pul_TorCounterValue) | -+----------------------------------------------------------------------------+ -| Task case APCI1710_TOR_GETPROGRESSSTATUS: Return the tor counter -(b_TorCounter) status (pb_TorCounterStatus) from selected tor counter | -| module (b_ModulNbr). - - case APCI1710_TOR_GETCOUNTERVALUE : - Return the tor counter (b_TorCounter) status | -| (pb_TorCounterStatus) and the timing value | -| (pul_TorCounterValue) after a conting cycle stop | -| from selected tor counter module (b_ModulNbr). | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3) | -| unsigned char_ b_TorCounter : Tor counter selection (0 or 1). - b_ModulNbr = CR_AREF(insn->chanspec); - b_ReadType = (unsigned char) data[0]; - b_TorCounter = (unsigned char) data[1]; - ui_TimeOut = (unsigned int) data[2]; | -+----------------------------------------------------------------------------+ -| Output Parameters : unsigned char *_ pb_TorCounterStatus : Return the tor counter | -| status. | -| 0 : Conting cycle not started| -| Software gate not set. | -| 1 : Conting cycle started. | -| Software gate set. | -| 2 : Conting cycle stopped. | -| The conting cycle is | -| terminate. | -| 3 : A overflow occur. You | -| must change the base | -| timing witch the | -| function | -| "i_APCI1710_InitTorCounter"| -| 4 : Timeeout occur | -| unsigned int * pul_TorCounterValue : Tor counter value. - pb_TorCounterStatus=(unsigned char *) &data[0]; - pul_TorCounterValue=(unsigned int *) &data[1]; | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: Module selection wrong | -| -3: The module is not a tor counter module | -| -4: Tor counter selection is wrong | -| -5: Tor counter not initialised see function | -| "i_APCI1710_InitTorCounter" | -| -6: Tor counter not enabled see function | -| "i_APCI1710_EnableTorCounter" | -| -7: Timeout parameter is wrong (0 to 65535) | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_Status; - unsigned int dw_TimeOut = 0; - - unsigned char b_ModulNbr; - unsigned char b_TorCounter; - unsigned char b_ReadType; - unsigned int ui_TimeOut; - unsigned char *pb_TorCounterStatus; - unsigned int *pul_TorCounterValue; - - i_ReturnValue = insn->n; - b_ModulNbr = CR_AREF(insn->chanspec); - b_ReadType = (unsigned char) data[0]; - b_TorCounter = (unsigned char) data[1]; - ui_TimeOut = (unsigned int) data[2]; - pb_TorCounterStatus = (unsigned char *) &data[0]; - pul_TorCounterValue = (unsigned int *) &data[1]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ReadType == APCI1710_TOR_READINTERRUPT) { - - data[0] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].b_OldModuleMask; - data[1] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldInterruptMask; - data[2] = devpriv->s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters.ui_Read].ul_OldCounterLatchValue; - - /**************************/ - /* Increment the read FIFO */ - /***************************/ - - devpriv-> - s_InterruptParameters. - ui_Read = (devpriv-> - s_InterruptParameters. - ui_Read + 1) % APCI1710_SAVE_INTERRUPT; - - return insn->n; - } - - if (b_ModulNbr < 4) { - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - /**********************************/ - /* Test the tor counter selection */ - /**********************************/ - - if (b_TorCounter <= 1) { - /***********************************/ - /* Test if tor counter initialised */ - /***********************************/ - - dw_Status = inl(devpriv->s_BoardInfos. - ui_Address + 8 + (16 * b_TorCounter) + - (64 * b_ModulNbr)); - - /*******************************/ - /* Test if counter initialised */ - /*******************************/ - - if (dw_Status & 0x10) { - /***************************/ - /* Test if counter enabled */ - /***************************/ - - if (dw_Status & 0x1) { - - switch (b_ReadType) { - - case APCI1710_TOR_GETPROGRESSSTATUS: - /*******************/ - /* Read the status */ - /*******************/ - - dw_Status = - inl(devpriv-> - s_BoardInfos. - ui_Address + 4 + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - dw_Status = - dw_Status & 0xF; - - /*****************/ - /* Test if start */ - /*****************/ - - if (dw_Status & 1) { - if (dw_Status & - 2) { - if (dw_Status & 4) { - /************************/ - /* Tor counter overflow */ - /************************/ - - *pb_TorCounterStatus - = - 3; - } else { - /***********************/ - /* Tor counter started */ - /***********************/ - - *pb_TorCounterStatus - = - 2; - } - } else { - /***********************/ - /* Tor counter started */ - /***********************/ - - *pb_TorCounterStatus - = - 1; - } - } else { - /***************************/ - /* Tor counter not started */ - /***************************/ - - *pb_TorCounterStatus - = 0; - } - break; - - case APCI1710_TOR_GETCOUNTERVALUE: - - /*****************************/ - /* Test the timout parameter */ - /*****************************/ - - if ((ui_TimeOut >= 0) - && (ui_TimeOut - <= - 65535UL)) - { - for (;;) { - /*******************/ - /* Read the status */ - /*******************/ - - dw_Status - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 4 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - /********************/ - /* Test if overflow */ - /********************/ - - if ((dw_Status & 4) == 4) { - /******************/ - /* Overflow occur */ - /******************/ - - *pb_TorCounterStatus - = - 3; - - /******************/ - /* Read the value */ - /******************/ - - *pul_TorCounterValue - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 0 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - break; - } /* if ((dw_Status & 4) == 4) */ - else { - /*******************************/ - /* Test if measurement stopped */ - /*******************************/ - - if ((dw_Status & 2) == 2) { - /***********************/ - /* A stop signal occur */ - /***********************/ - - *pb_TorCounterStatus - = - 2; - - /******************/ - /* Read the value */ - /******************/ - - *pul_TorCounterValue - = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - 0 - + - (16 * b_TorCounter) + (64 * b_ModulNbr)); - - break; - } /* if ((dw_Status & 2) == 2) */ - else { - /*******************************/ - /* Test if measurement started */ - /*******************************/ - - if ((dw_Status & 1) == 1) { - /************************/ - /* A start signal occur */ - /************************/ - - *pb_TorCounterStatus - = - 1; - } /* if ((dw_Status & 1) == 1) */ - else { - /***************************/ - /* Measurement not started */ - /***************************/ - - *pb_TorCounterStatus - = - 0; - } /* if ((dw_Status & 1) == 1) */ - } /* if ((dw_Status & 2) == 2) */ - } /* if ((dw_Status & 8) == 8) */ - - if (dw_TimeOut == ui_TimeOut) { - /*****************/ - /* Timeout occur */ - /*****************/ - - break; - } else { - /*************************/ - /* Increment the timeout */ - /*************************/ - - dw_TimeOut - = - dw_TimeOut - + - 1; - - mdelay(1000); - } - } /* for (;;) */ - - /*************************/ - /* Test if timeout occur */ - /*************************/ - - if ((*pb_TorCounterStatus != 3) && (dw_TimeOut == ui_TimeOut) && (ui_TimeOut != 0)) { - /*****************/ - /* Timeout occur */ - /*****************/ - - *pb_TorCounterStatus - = - 4; - } - } else { - /******************************/ - /* Timeout parameter is wrong */ - /******************************/ - - DPRINTK("Timeout parameter is wrong\n"); - i_ReturnValue = - -7; - } - break; - - default: - printk("Inputs wrong\n"); - } /* switch end */ - } /* if (dw_Status & 0x1) */ - else { - /***************************/ - /* Tor counter not enabled */ - /***************************/ - - DPRINTK("Tor counter not enabled\n"); - i_ReturnValue = -6; - } /* if (dw_Status & 0x1) */ - } else { - /*******************************/ - /* Tor counter not initialised */ - /*******************************/ - - DPRINTK("Tor counter not initialised\n"); - i_ReturnValue = -5; - } - } /* if (b_TorCounter <= 1) */ - else { - /**********************************/ - /* Tor counter selection is wrong */ - /**********************************/ - - DPRINTK("Tor counter selection is wrong\n"); - i_ReturnValue = -4; - } /* if (b_TorCounter <= 1) */ - } else { - /******************************************/ - /* The module is not a tor counter module */ - /******************************************/ - - DPRINTK("The module is not a tor counter module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h deleted file mode 100644 index 537d4755132..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Tor.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_30MHZ 30 -#define APCI1710_33MHZ 33 -#define APCI1710_40MHZ 40 - -#define APCI1710_GATE_INPUT 10 - -#define APCI1710_TOR_SIMPLE_MODE 2 -#define APCI1710_TOR_DOUBLE_MODE 3 -#define APCI1710_TOR_QUADRUPLE_MODE 4 - -#define APCI1710_SINGLE 0 -#define APCI1710_CONTINUOUS 1 - -#define APCI1710_TOR_GETPROGRESSSTATUS 0 -#define APCI1710_TOR_GETCOUNTERVALUE 1 -#define APCI1710_TOR_READINTERRUPT 2 - -/* - * TOR_COUNTER INISIALISATION FUNCTION - */ -int i_APCI1710_InsnConfigInitTorCounter(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1710_InsnWriteEnableDisableTorCounter(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -int i_APCI1710_InsnReadGetTorCounterInitialisation(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -/* - * TOR_COUNTER READ FUNCTION - */ -int i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c deleted file mode 100644 index 9e177f4af86..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.c +++ /dev/null @@ -1,1038 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1710 | Compiler : gcc | - | Module name : TTL.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : APCI-1710 TTL I/O module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 13/05/98 | S. Weber | TTL digital input / output implementation | - |----------|-----------|------------------------------------------------| - | 08/05/00 | Guinot C | - 0400/0228 All Function in RING 0 | - | | | available | - +-----------------------------------------------------------------------+ - | | | | - | | | | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ - -#include "APCI1710_Ttl.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_InitTTLIODirection | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_PortAMode, | -| unsigned char_ b_PortBMode, | -| unsigned char_ b_PortCMode, | -| unsigned char_ b_PortDMode) | -+----------------------------------------------------------------------------+ -| Task APCI1710_TTL_INIT (using defaults) : Configure the TTL I/O operating mode from selected | -| module (b_ModulNbr). You must calling this function be| -| for you call any other function witch access of TTL. | - APCI1710_TTL_INITDIRECTION(user inputs for direction) - -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_InitType = (unsigned char) data[0]; - b_PortAMode = (unsigned char) data[1]; - b_PortBMode = (unsigned char) data[2]; - b_PortCMode = (unsigned char) data[3]; - b_PortDMode = (unsigned char) data[4];| -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a TTL module | -| -4: Function not available for this version | -| -5: Port A mode selection is wrong | -| -6: Port B mode selection is wrong | -| -7: Port C mode selection is wrong | -| -8: Port D mode selection is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned char b_ModulNbr; - unsigned char b_InitType; - unsigned char b_PortAMode; - unsigned char b_PortBMode; - unsigned char b_PortCMode; - unsigned char b_PortDMode; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - b_InitType = (unsigned char) data[0]; - i_ReturnValue = insn->n; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /**************************/ - /* Test if TTL I/O module */ - /**************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TTL_IO) { - switch (b_InitType) { - case APCI1710_TTL_INIT: - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_TTLInit = 1; - - /***************************/ - /* Set TTL port A to input */ - /***************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_PortConfiguration[0] = 0; - - /***************************/ - /* Set TTL port B to input */ - /***************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_PortConfiguration[1] = 0; - - /***************************/ - /* Set TTL port C to input */ - /***************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_PortConfiguration[2] = 0; - - /****************************/ - /* Set TTL port D to output */ - /****************************/ - - devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_PortConfiguration[3] = 1; - - /*************************/ - /* Set the configuration */ - /*************************/ - - outl(0x8, - devpriv->s_BoardInfos.ui_Address + 20 + - (64 * b_ModulNbr)); - break; - - case APCI1710_TTL_INITDIRECTION: - - b_PortAMode = (unsigned char) data[1]; - b_PortBMode = (unsigned char) data[2]; - b_PortCMode = (unsigned char) data[3]; - b_PortDMode = (unsigned char) data[4]; - - /********************/ - /* Test the version */ - /********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & 0xFFFF) >= - 0x3230) { - /************************/ - /* Test the port A mode */ - /************************/ - - if ((b_PortAMode == 0) - || (b_PortAMode == 1)) { - /************************/ - /* Test the port B mode */ - /************************/ - - if ((b_PortBMode == 0) - || (b_PortBMode == 1)) { - /************************/ - /* Test the port C mode */ - /************************/ - - if ((b_PortCMode == 0) - || (b_PortCMode - == 1)) { - /************************/ - /* Test the port D mode */ - /************************/ - - if ((b_PortDMode == 0) || (b_PortDMode == 1)) { - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_TTLInit - = - 1; - - /***********************/ - /* Set TTL port A mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [0] - = - b_PortAMode; - - /***********************/ - /* Set TTL port B mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [1] - = - b_PortBMode; - - /***********************/ - /* Set TTL port C mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [2] - = - b_PortCMode; - - /***********************/ - /* Set TTL port D mode */ - /***********************/ - - devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [3] - = - b_PortDMode; - - /*************************/ - /* Set the configuration */ - /*************************/ - - outl((b_PortAMode << 0) | (b_PortBMode << 1) | (b_PortCMode << 2) | (b_PortDMode << 3), devpriv->s_BoardInfos.ui_Address + 20 + (64 * b_ModulNbr)); - } else { - /**********************************/ - /* Port D mode selection is wrong */ - /**********************************/ - - DPRINTK("Port D mode selection is wrong\n"); - i_ReturnValue - = - -8; - } - } else { - /**********************************/ - /* Port C mode selection is wrong */ - /**********************************/ - - DPRINTK("Port C mode selection is wrong\n"); - i_ReturnValue = - -7; - } - } else { - /**********************************/ - /* Port B mode selection is wrong */ - /**********************************/ - - DPRINTK("Port B mode selection is wrong\n"); - i_ReturnValue = -6; - } - } else { - /**********************************/ - /* Port A mode selection is wrong */ - /**********************************/ - - DPRINTK("Port A mode selection is wrong\n"); - i_ReturnValue = -5; - } - } else { - /*******************************************/ - /* Function not available for this version */ - /*******************************************/ - - DPRINTK("Function not available for this version\n"); - i_ReturnValue = -4; - } - break; - - DPRINTK("\n"); - default: - printk("Bad Config Type\n"); - } /* switch end */ - } else { - /**********************************/ - /* The module is not a TTL module */ - /**********************************/ - - DPRINTK("The module is not a TTL module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_ReadTTLIOChannelValue | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_SelectedPort, | -| unsigned char_ b_InputChannel, | -| unsigned char *_ pb_ChannelStatus) | -+----------------------------------------------------------------------------+ -| Task : Read the status from selected TTL digital input | -| (b_InputChannel) -+----------------------------------------------------------------------------+ -| Task : Read the status from digital input port | -| (b_SelectedPort) from selected TTL module (b_ModulNbr) | -+----------------------------------------------------------------------------+ - -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 7) | -| unsigned char_ b_SelectedPort, : Selection from TTL I/O | -| port (0 to 2) | -| 0 : Port A selection | -| 1 : Port B selection | -| 2 : Port C selection | -| 3 : Port D selection | -| unsigned char_ b_InputChannel : Selection from digital | -| input ( 0 to 2) -APCI1710_TTL_READCHANNEL - b_ModulNbr = CR_AREF(insn->chanspec); - b_SelectedPort= CR_RANGE(insn->chanspec); - b_InputChannel= CR_CHAN(insn->chanspec); - b_ReadType = (unsigned char) data[0]; - - APCI1710_TTL_READPORT| - b_ModulNbr = CR_AREF(insn->chanspec); - b_SelectedPort= CR_RANGE(insn->chanspec); - b_ReadType = (unsigned char) data[0]; - -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] - - unsigned char *_ pb_ChannelStatus : Digital input channel | -| status | -| 0 : Channle is not active| -| 1 : Channle is active | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a TTL module | -| -4: The selected TTL input port is wrong | -| -5: The selected TTL digital input is wrong | -| -6: TTL I/O not initialised | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr; - unsigned char b_SelectedPort; - unsigned char b_InputChannel; - unsigned char b_ReadType; - unsigned char *pb_ChannelStatus; - unsigned char *pb_PortValue; - - i_ReturnValue = insn->n; - b_ReadType = (unsigned char) data[0]; - b_ModulNbr = CR_AREF(insn->chanspec); - b_SelectedPort = CR_RANGE(insn->chanspec); - b_InputChannel = CR_CHAN(insn->chanspec); - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /**************************/ - /* Test if TTL I/O module */ - /**************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TTL_IO) { - switch (b_ReadType) { - - case APCI1710_TTL_READCHANNEL: - pb_ChannelStatus = (unsigned char *) &data[0]; - /********************************/ - /* Test the TTL I/O port number */ - /********************************/ - - if (((b_SelectedPort <= 2) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) == - 0x3130)) - || ((b_SelectedPort <= 3) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) >= - 0x3230))) { - /******************************************/ - /* Test the digital imnput channel number */ - /******************************************/ - - if (((b_InputChannel <= 7) - && (b_SelectedPort < 3)) - || ((b_InputChannel <= 1) - && (b_SelectedPort == - 3))) { - /******************************************/ - /* Test if the TTL I/O module initialised */ - /******************************************/ - - if (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo.b_TTLInit == - 1) { - /***********************************/ - /* Test if TTL port used for input */ - /***********************************/ - - if (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) == 0x3130) || (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) { - /**************************/ - /* Read all digital input */ - /**************************/ - - dw_StatusReg = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - (64 * b_ModulNbr)); - - *pb_ChannelStatus - = - (unsigned char) ( - (dw_StatusReg - >> - (8 * b_SelectedPort)) >> b_InputChannel) & 1; - } else { - /*******************************/ - /* Selected TTL I/O port error */ - /*******************************/ - - DPRINTK("Selected TTL I/O port error\n"); - i_ReturnValue = - -4; - } - } else { - /***************************/ - /* TTL I/O not initialised */ - /***************************/ - - DPRINTK("TTL I/O not initialised\n"); - i_ReturnValue = -6; - } - } else { - /********************************/ - /* Selected digital input error */ - /********************************/ - - DPRINTK("Selected digital input error\n"); - i_ReturnValue = -5; - } - } else { - /*******************************/ - /* Selected TTL I/O port error */ - /*******************************/ - - DPRINTK("Selected TTL I/O port error\n"); - i_ReturnValue = -4; - } - break; - - case APCI1710_TTL_READPORT: - pb_PortValue = (unsigned char *) &data[0]; - /********************************/ - /* Test the TTL I/O port number */ - /********************************/ - - if (((b_SelectedPort <= 2) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) == - 0x3130)) - || ((b_SelectedPort <= 3) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) >= - 0x3230))) { - /******************************************/ - /* Test if the TTL I/O module initialised */ - /******************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_TTLInit == 1) { - /***********************************/ - /* Test if TTL port used for input */ - /***********************************/ - - if (((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] - & - 0xFFFF) - == 0x3130) - || (((devpriv->s_BoardInfos.dw_MolduleConfiguration[b_ModulNbr] & 0xFFFF) >= 0x3230) && (devpriv->s_ModuleInfo[b_ModulNbr].s_TTLIOInfo.b_PortConfiguration[b_SelectedPort] == 0))) { - /**************************/ - /* Read all digital input */ - /**************************/ - - dw_StatusReg = - inl(devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - - *pb_PortValue = - (unsigned char) ( - (dw_StatusReg >> - (8 * b_SelectedPort)) & 0xFF); - } else { - /*******************************/ - /* Selected TTL I/O port error */ - /*******************************/ - - DPRINTK("Selected TTL I/O port error\n"); - i_ReturnValue = -4; - } - } else { - /***************************/ - /* TTL I/O not initialised */ - /***************************/ - - DPRINTK("TTL I/O not initialised\n"); - i_ReturnValue = -5; - } - } else { - /*******************************/ - /* Selected TTL I/O port error */ - /*******************************/ - - DPRINTK("Selected TTL I/O port error\n"); - i_ReturnValue = -4; - } - break; - - default: - printk("Bad ReadType\n"); - - } /* End Switch */ - } else { - /**********************************/ - /* The module is not a TTL module */ - /**********************************/ - - DPRINTK("The module is not a TTL module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1710_InsnReadTTLIOAllPortValue(comedi_device -*dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the status from all digital input ports | -| (port A, port B and port C) from selected TTL | -| module (b_ModulNbr) | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710| -| unsigned char_ b_ModulNbr : Module number to | -| configure (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : PULONG_ pul_PortValue : Digital TTL inputs port | -| status | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a TTL module | -| -4: TTL I/O not initialised | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg; - unsigned char b_ModulNbr; - unsigned int *pul_PortValue; - - b_ModulNbr = (unsigned char) CR_AREF(insn->chanspec); - i_ReturnValue = insn->n; - pul_PortValue = (unsigned int *) &data[0]; - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /**************************/ - /* Test if TTL I/O module */ - /**************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TTL_IO) { - /******************************************/ - /* Test if the TTL I/O module initialised */ - /******************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_TTLInit == 1) { - /**************************/ - /* Read all digital input */ - /**************************/ - - dw_StatusReg = inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModulNbr)); - - /**********************/ - /* Test if TTL Rev1.0 */ - /**********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & 0xFFFF) == - 0x3130) { - *pul_PortValue = - dw_StatusReg & 0xFFFFFFUL; - } else { - /**************************************/ - /* Test if port A not used for output */ - /**************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration[0] == 1) { - *pul_PortValue = - dw_StatusReg & - 0x3FFFF00UL; - } - - /**************************************/ - /* Test if port B not used for output */ - /**************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration[1] == 1) { - *pul_PortValue = - dw_StatusReg & - 0x3FF00FFUL; - } - - /**************************************/ - /* Test if port C not used for output */ - /**************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration[2] == 1) { - *pul_PortValue = - dw_StatusReg & - 0x300FFFFUL; - } - - /**************************************/ - /* Test if port D not used for output */ - /**************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration[3] == 1) { - *pul_PortValue = - dw_StatusReg & - 0xFFFFFFUL; - } - } - } else { - /***************************/ - /* TTL I/O not initialised */ - /***************************/ - DPRINTK("TTL I/O not initialised\n"); - i_ReturnValue = -5; - } - } else { - /**********************************/ - /* The module is not a TTL module */ - /**********************************/ - DPRINTK("The module is not a TTL module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : _INT_ i_APCI1710_SetTTLIOChlOn | -| (unsigned char_ b_BoardHandle, | -| unsigned char_ b_ModulNbr, | -| unsigned char_ b_OutputChannel) -int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Sets or resets the output witch has been passed with the | -| parameter b_Channel. Setting an output means setting | -| an ouput high. | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char_ b_BoardHandle : Handle of board APCI-1710 | -| unsigned char_ b_ModulNbr : Selected module number (0 to 3)| -| unsigned char_ b_OutputChannel : Selection from digital output | -| channel (0 or 1) | -| 0 : PD0 | -| 1 : PD1 | -| 2 to 9 : PA | -| 10 to 17: PB | -| 18 to 25: PC | - - b_ModulNbr = CR_AREF(insn->chanspec); - b_OutputChannel= CR_CHAN(insn->chanspec); - ui_State = data[0]; /* ON or OFF */ -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -1: The handle parameter of the board is wrong | -| -2: The module parameter is wrong | -| -3: The module is not a TTL I/O module | -| -4: The selected digital output is wrong | -| -5: TTL I/O not initialised see function | -| " i_APCI1710_InitTTLIO" -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = 0; - unsigned int dw_StatusReg = 0; - unsigned char b_ModulNbr; - unsigned char b_OutputChannel; - unsigned int ui_State; - - i_ReturnValue = insn->n; - b_ModulNbr = CR_AREF(insn->chanspec); - b_OutputChannel = CR_CHAN(insn->chanspec); - ui_State = data[0]; /* ON or OFF */ - - /**************************/ - /* Test the module number */ - /**************************/ - - if (b_ModulNbr < 4) { - /**************************/ - /* Test if TTL I/O module */ - /**************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModulNbr] & - 0xFFFF0000UL) == APCI1710_TTL_IO) { - /******************************************/ - /* Test if the TTL I/O module initialised */ - /******************************************/ - - if (devpriv->s_ModuleInfo[b_ModulNbr]. - s_TTLIOInfo.b_TTLInit == 1) { - /***********************************/ - /* Test the TTL I/O channel number */ - /***********************************/ - - if (((b_OutputChannel <= 1) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) == - 0x3130)) - || ((b_OutputChannel <= 25) - && ((devpriv->s_BoardInfos. - dw_MolduleConfiguration - [b_ModulNbr] & - 0xFFFF) >= - 0x3230))) { - /****************************************************/ - /* Test if the selected channel is a output channel */ - /****************************************************/ - - if (((b_OutputChannel <= 1) - && (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [3] == 1)) - || ((b_OutputChannel >= 2) - && (b_OutputChannel <= - 9) - && (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [0] == 1)) - || ((b_OutputChannel >= 10) - && (b_OutputChannel <= - 17) - && (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [1] == 1)) - || ((b_OutputChannel >= 18) - && (b_OutputChannel <= - 25) - && (devpriv-> - s_ModuleInfo - [b_ModulNbr]. - s_TTLIOInfo. - b_PortConfiguration - [2] == 1))) { - /************************/ - /* Test if PD0 selected */ - /************************/ - - if (b_OutputChannel == 0) { - - outl(ui_State, - devpriv-> - s_BoardInfos. - ui_Address + - (64 * b_ModulNbr)); - } else { - /************************/ - /* Test if PD1 selected */ - /************************/ - - if (b_OutputChannel == - 1) { - - outl(ui_State, - devpriv-> - s_BoardInfos. - ui_Address - + 4 + - (64 * b_ModulNbr)); - } else { - b_OutputChannel - = - b_OutputChannel - - 2; - - /********************/ - /* Read all channel */ - /********************/ - - dw_StatusReg = - inl - (devpriv-> - s_BoardInfos. - ui_Address - + - (64 * b_ModulNbr)); - if (ui_State) /* ON */ - { - dw_StatusReg - = - (dw_StatusReg - >> - ((b_OutputChannel / 8) * 8)) & 0xFF; - dw_StatusReg - = - dw_StatusReg - | - (1 - << - (b_OutputChannel - % - 8)); - } else /* Off */ - { - dw_StatusReg - = - (dw_StatusReg - >> - ((b_OutputChannel / 8) * 8)) & 0xFF; - dw_StatusReg - = - dw_StatusReg - & - (0xFF - - - (1 << (b_OutputChannel % 8))); - - } - - /****************************/ - /* Set the new output value */ - /****************************/ - - outl(dw_StatusReg, devpriv->s_BoardInfos.ui_Address + 8 + ((b_OutputChannel / 8) * 4) + (64 * b_ModulNbr)); - } - } - } else { - /************************************/ - /* The selected TTL output is wrong */ - /************************************/ - - DPRINTK(" The selected TTL output is wrong\n"); - i_ReturnValue = -4; - } - } else { - /************************************/ - /* The selected TTL output is wrong */ - /************************************/ - - DPRINTK("The selected TTL output is wrong\n"); - i_ReturnValue = -4; - } - } else { - /***************************/ - /* TTL I/O not initialised */ - /***************************/ - - DPRINTK("TTL I/O not initialised\n"); - i_ReturnValue = -5; - } - } else { - /**************************************/ - /* The module is not a TTL I/O module */ - /**************************************/ - - DPRINTK("The module is not a TTL I/O module\n"); - i_ReturnValue = -3; - } - } else { - /***********************/ - /* Module number error */ - /***********************/ - - DPRINTK("Module number error\n"); - i_ReturnValue = -2; - } - - return i_ReturnValue; -} diff --git a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h b/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h deleted file mode 100644 index adcab824b25..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/APCI1710_Ttl.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * 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. - */ - -#define APCI1710_TTL_INIT 0 -#define APCI1710_TTL_INITDIRECTION 1 - -#define APCI1710_TTL_READCHANNEL 0 -#define APCI1710_TTL_READPORT 1 - -/* - * TTL INISIALISATION FUNCTION - */ -int i_APCI1710_InsnConfigInitTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * TTL INPUT FUNCTION - */ -int i_APCI1710_InsnBitsReadTTLIO(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1710_InsnReadTTLIOAllPortValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * TTL OUTPUT FUNCTIONS - */ -int i_APCI1710_InsnWriteSetTTLIOChlOnOff(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c deleted file mode 100644 index b973095146f..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c +++ /dev/null @@ -1,195 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : ADDI HEADER READ WRITER | Compiler : Visual C++ | - | Module name : S5920.cpp | Version : 6.0 | - +-------------------------------+---------------------------------------+ - | Author : E. LIBS Date : 02/05/2002 | - +-----------------------------------------------------------------------+ - | Description : DLL with the S5920 PCI Controller functions | - +-----------------------------------------------------------------------+ - | UPDATE'S | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 28/08/02 | LIBS Eric | Add return codes each time a function of the | - | | | Addi Library is called | - +-----------------------------------------------------------------------+ - | 31/07/03 | KRAUTH J. | Changes for the MSX-Box | - +-----------------------------------------------------------------------+ -*/ - -#include "addi_amcc_S5920.h" - -/*+----------------------------------------------------------------------------+*/ -/*| Function Name : int i_AddiHeaderRW_ReadEeprom |*/ -/*| (int i_NbOfWordsToRead, |*/ -/*| unsigned int dw_PCIBoardEepromAddress, |*/ -/*| unsigned short w_EepromStartAddress, |*/ -/*| unsigned short * pw_DataRead) |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Task : Read word from the 5920 eeprom. |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Input Parameters : int i_NbOfWordsToRead : Nbr. of word to read |*/ -/*| unsigned int dw_PCIBoardEepromAddress : Address of the eeprom |*/ -/*| unsigned short w_EepromStartAddress : Eeprom start address |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Output Parameters : unsigned short * pw_DataRead : Read data |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Return Value : - |*/ -/*+----------------------------------------------------------------------------+*/ - -int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, - unsigned int dw_PCIBoardEepromAddress, - unsigned short w_EepromStartAddress, unsigned short *pw_DataRead) -{ - unsigned int dw_eeprom_busy = 0; - int i_Counter = 0; - int i_WordCounter; - int i; - unsigned char pb_ReadByte[1]; - unsigned char b_ReadLowByte = 0; - unsigned char b_ReadHighByte = 0; - unsigned char b_SelectedAddressLow = 0; - unsigned char b_SelectedAddressHigh = 0; - unsigned short w_ReadWord = 0; - - for (i_WordCounter = 0; i_WordCounter < i_NbOfWordsToRead; - i_WordCounter++) { - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - for (i_Counter = 0; i_Counter < 2; i_Counter++) { - b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256; /* Read the low 8 bit part */ - b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256; /* Read the high 8 bit part */ - - /* Select the load low address mode */ - outb(NVCMD_LOAD_LOW, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Load the low address */ - outb(b_SelectedAddressLow, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the load high address mode */ - outb(NVCMD_LOAD_HIGH, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Load the high address */ - outb(b_SelectedAddressHigh, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the READ mode */ - outb(NVCMD_BEGIN_READ, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Read data into the EEPROM */ - *pb_ReadByte = - inb(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR + 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the upper address part */ - if (i_Counter == 0) - b_ReadLowByte = pb_ReadByte[0]; - else - b_ReadHighByte = pb_ReadByte[0]; - - /* Sleep */ - msleep(1); - - } - w_ReadWord = - (b_ReadLowByte | (((unsigned short)b_ReadHighByte) * - 256)); - - pw_DataRead[i_WordCounter] = w_ReadWord; - - w_EepromStartAddress += 2; /* to read the next word */ - - } /* for (...) i_NbOfWordsToRead */ - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h deleted file mode 100644 index 9afdb1357aa..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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. - */ - -#define AMCC_OP_REG_MCSR 0x3c -#define EEPROM_BUSY 0x80000000 -#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ -#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ -#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ -#define NVCMD_BEGIN_WRITE (0x6 << 5) /* EEPROM begin write command */ - -int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, - unsigned int dw_PCIBoardEepromAddress, - unsigned short w_EepromStartAddress, unsigned short *pw_DataRead); diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h b/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h deleted file mode 100644 index 35a3ea19359..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_s5933.h +++ /dev/null @@ -1,475 +0,0 @@ -/* - * 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. - */ - -/* Header file for AMCC s 5933 */ - -#ifndef _AMCC_S5933_H_ -#define _AMCC_S5933_H_ - -#include "../../comedidev.h" - -#include "../comedi_pci.h" - -#ifdef PCI_SUPPORT_VER1 -#error No support for 2.1.55 and older -#endif - -/* written on base0 */ -#define FIFO_ADVANCE_ON_BYTE_2 0x20000000 - -/* added for step 6 dma written on base2 */ -#define AMWEN_ENABLE 0x02 - -#define A2P_FIFO_WRITE_ENABLE 0x01 - -/* for transfer count enable bit */ -#define AGCSTS_TC_ENABLE 0x10000000 - -/* - * ADDON RELATED ADDITIONS - */ -/* Constant */ -#define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00 -#define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200 -#define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L -#define APCI3120_AMWEN_ENABLE 0x02 -#define APCI3120_A2P_FIFO_WRITE_ENABLE 0x01 -#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 0x20000000L -#define APCI3120_ENABLE_WRITE_TC_INT 0x00004000L -#define APCI3120_CLEAR_WRITE_TC_INT 0x00040000L -#define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0 -#define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0 -#define APCI3120_DISABLE_BUS_MASTER_PCI 0x0 - -/* ADD_ON ::: this needed since apci supports 16 bit interface to add on */ -#define APCI3120_ADD_ON_AGCSTS_LOW 0x3C -#define APCI3120_ADD_ON_AGCSTS_HIGH (APCI3120_ADD_ON_AGCSTS_LOW + 2) -#define APCI3120_ADD_ON_MWAR_LOW 0x24 -#define APCI3120_ADD_ON_MWAR_HIGH (APCI3120_ADD_ON_MWAR_LOW + 2) -#define APCI3120_ADD_ON_MWTC_LOW 0x058 -#define APCI3120_ADD_ON_MWTC_HIGH (APCI3120_ADD_ON_MWTC_LOW + 2) - -/* AMCC */ -#define APCI3120_AMCC_OP_MCSR 0x3C -#define APCI3120_AMCC_OP_REG_INTCSR 0x38 - -/* - * AMCC Operation Register Offsets - PCI - */ -#define AMCC_OP_REG_OMB1 0x00 -#define AMCC_OP_REG_OMB2 0x04 -#define AMCC_OP_REG_OMB3 0x08 -#define AMCC_OP_REG_OMB4 0x0c -#define AMCC_OP_REG_IMB1 0x10 -#define AMCC_OP_REG_IMB2 0x14 -#define AMCC_OP_REG_IMB3 0x18 -#define AMCC_OP_REG_IMB4 0x1c -#define AMCC_OP_REG_FIFO 0x20 -#define AMCC_OP_REG_MWAR 0x24 -#define AMCC_OP_REG_MWTC 0x28 -#define AMCC_OP_REG_MRAR 0x2c -#define AMCC_OP_REG_MRTC 0x30 -#define AMCC_OP_REG_MBEF 0x34 -#define AMCC_OP_REG_INTCSR 0x38 -/* int source */ -#define AMCC_OP_REG_INTCSR_SRC (AMCC_OP_REG_INTCSR + 2) -/* FIFO ctrl */ -#define AMCC_OP_REG_INTCSR_FEC (AMCC_OP_REG_INTCSR + 3) -#define AMCC_OP_REG_MCSR 0x3c -/* Data in byte 2 */ -#define AMCC_OP_REG_MCSR_NVDATA (AMCC_OP_REG_MCSR + 2) -/* Command in byte 3 */ -#define AMCC_OP_REG_MCSR_NVCMD (AMCC_OP_REG_MCSR + 3) - -#define AMCC_FIFO_DEPTH_DWORD 8 -#define AMCC_FIFO_DEPTH_BYTES (8 * sizeof(u32)) - -/* - * AMCC Operation Registers Size - PCI - */ -#define AMCC_OP_REG_SIZE 64 /* in bytes */ - -/* - * AMCC Operation Register Offsets - Add-on - */ -#define AMCC_OP_REG_AIMB1 0x00 -#define AMCC_OP_REG_AIMB2 0x04 -#define AMCC_OP_REG_AIMB3 0x08 -#define AMCC_OP_REG_AIMB4 0x0c -#define AMCC_OP_REG_AOMB1 0x10 -#define AMCC_OP_REG_AOMB2 0x14 -#define AMCC_OP_REG_AOMB3 0x18 -#define AMCC_OP_REG_AOMB4 0x1c -#define AMCC_OP_REG_AFIFO 0x20 -#define AMCC_OP_REG_AMWAR 0x24 -#define AMCC_OP_REG_APTA 0x28 -#define AMCC_OP_REG_APTD 0x2c -#define AMCC_OP_REG_AMRAR 0x30 -#define AMCC_OP_REG_AMBEF 0x34 -#define AMCC_OP_REG_AINT 0x38 -#define AMCC_OP_REG_AGCSTS 0x3c -#define AMCC_OP_REG_AMWTC 0x58 -#define AMCC_OP_REG_AMRTC 0x5c - -/* - * AMCC - Add-on General Control/Status Register - */ -#define AGCSTS_CONTROL_MASK 0xfffff000 -#define AGCSTS_NV_ACC_MASK 0xe0000000 -#define AGCSTS_RESET_MASK 0x0e000000 -#define AGCSTS_NV_DA_MASK 0x00ff0000 -#define AGCSTS_BIST_MASK 0x0000f000 -#define AGCSTS_STATUS_MASK 0x000000ff -#define AGCSTS_TCZERO_MASK 0x000000c0 -#define AGCSTS_FIFO_ST_MASK 0x0000003f - -#define AGCSTS_RESET_MBFLAGS 0x08000000 -#define AGCSTS_RESET_P2A_FIFO 0x04000000 -#define AGCSTS_RESET_A2P_FIFO 0x02000000 -#define AGCSTS_RESET_FIFOS (AGCSTS_RESET_A2P_FIFO | AGCSTS_RESET_P2A_FIFO) - -#define AGCSTS_A2P_TCOUNT 0x00000080 -#define AGCSTS_P2A_TCOUNT 0x00000040 - -#define AGCSTS_FS_P2A_EMPTY 0x00000020 -#define AGCSTS_FS_P2A_HALF 0x00000010 -#define AGCSTS_FS_P2A_FULL 0x00000008 - -#define AGCSTS_FS_A2P_EMPTY 0x00000004 -#define AGCSTS_FS_A2P_HALF 0x00000002 -#define AGCSTS_FS_A2P_FULL 0x00000001 - -/* - * AMCC - Add-on Interrupt Control/Status Register - */ -#define AINT_INT_MASK 0x00ff0000 -#define AINT_SEL_MASK 0x0000ffff -#define AINT_IS_ENSEL_MASK 0x00001f1f - -#define AINT_INT_ASSERTED 0x00800000 -#define AINT_BM_ERROR 0x00200000 -#define AINT_BIST_INT 0x00100000 - -#define AINT_RT_COMPLETE 0x00080000 -#define AINT_WT_COMPLETE 0x00040000 - -#define AINT_OUT_MB_INT 0x00020000 -#define AINT_IN_MB_INT 0x00010000 - -#define AINT_READ_COMPL 0x00008000 -#define AINT_WRITE_COMPL 0x00004000 - -#define AINT_OMB_ENABLE 0x00001000 -#define AINT_OMB_SELECT 0x00000c00 -#define AINT_OMB_BYTE 0x00000300 - -#define AINT_IMB_ENABLE 0x00000010 -#define AINT_IMB_SELECT 0x0000000c -#define AINT_IMB_BYTE 0x00000003 - -/* Enable Bus Mastering */ -#define EN_A2P_TRANSFERS 0x00000400 -/* FIFO Flag Reset */ -#define RESET_A2P_FLAGS 0x04000000L -/* FIFO Relative Priority */ -#define A2P_HI_PRIORITY 0x00000100L -/* Identify Interrupt Sources */ -#define ANY_S593X_INT 0x00800000L -#define READ_TC_INT 0x00080000L -#define WRITE_TC_INT 0x00040000L -#define IN_MB_INT 0x00020000L -#define MASTER_ABORT_INT 0x00100000L -#define TARGET_ABORT_INT 0x00200000L -#define BUS_MASTER_INT 0x00200000L - -/****************************************************************************/ - -struct pcilst_struct { - struct pcilst_struct *next; - int used; - struct pci_dev *pcidev; - unsigned short vendor; - unsigned short device; - unsigned char pci_bus; - unsigned char pci_slot; - unsigned char pci_func; - resource_size_t io_addr[5]; - unsigned int irq; -}; - -/* ptr to root list of all amcc devices */ -static struct pcilst_struct *amcc_devices; - -static const int i_ADDIDATADeviceID[] = { 0x15B8, 0x10E8 }; - -/****************************************************************************/ - -void v_pci_card_list_init(unsigned short pci_vendor, char display); -void v_pci_card_list_cleanup(unsigned short pci_vendor); -struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id, - unsigned short - device_id); -int i_find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card); -struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - int i_Master); - -int pci_card_alloc(struct pcilst_struct *amcc, int master); -int i_pci_card_free(struct pcilst_struct *amcc); -void v_pci_card_list_display(void); -int i_pci_card_data(struct pcilst_struct *amcc, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, resource_size_t * io_addr, - unsigned int *irq); - -/****************************************************************************/ - -/* build list of amcc cards in this system */ -void v_pci_card_list_init(unsigned short pci_vendor, char display) -{ - struct pci_dev *pcidev = NULL; - struct pcilst_struct *amcc, *last; - int i; - int i_Count = 0; - amcc_devices = NULL; - last = NULL; - - for_each_pci_dev(pcidev) { - for (i_Count = 0; i_Count < 2; i_Count++) { - pci_vendor = i_ADDIDATADeviceID[i_Count]; - if (pcidev->vendor == pci_vendor) { - amcc = kzalloc(sizeof(*amcc), GFP_KERNEL); - if (amcc == NULL) - continue; - - amcc->pcidev = pcidev; - if (last) - last->next = amcc; - else - amcc_devices = amcc; - last = amcc; - - amcc->vendor = pcidev->vendor; - amcc->device = pcidev->device; - amcc->pci_bus = pcidev->bus->number; - amcc->pci_slot = PCI_SLOT(pcidev->devfn); - amcc->pci_func = PCI_FUNC(pcidev->devfn); - /* Note: resources may be invalid if PCI device - * not enabled, but they are corrected in - * pci_card_alloc. */ - for (i = 0; i < 5; i++) - amcc->io_addr[i] = - pci_resource_start(pcidev, i); - amcc->irq = pcidev->irq; - - } - } - } - - if (display) - v_pci_card_list_display(); -} - -/****************************************************************************/ -/* free up list of amcc cards in this system */ -void v_pci_card_list_cleanup(unsigned short pci_vendor) -{ - struct pcilst_struct *amcc, *next; - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - kfree(amcc); - } - - amcc_devices = NULL; -} - -/****************************************************************************/ -/* find first unused card with this device_id */ -struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id, - unsigned short device_id) -{ - struct pcilst_struct *amcc, *next; - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - if ((!amcc->used) && (amcc->device == device_id) - && (amcc->vendor == vendor_id)) - return amcc; - - } - - return NULL; -} - -/****************************************************************************/ -/* find card on requested position */ -int i_find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card) -{ - struct pcilst_struct *amcc, *next; - - *card = NULL; - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - if ((amcc->vendor == vendor_id) && (amcc->device == device_id) - && (amcc->pci_bus == pci_bus) - && (amcc->pci_slot == pci_slot)) { - if (!(amcc->used)) { - *card = amcc; - return 0; /* ok, card is found */ - } else { - printk(" - \nCard on requested position is used b:s %d:%d!\n", - pci_bus, pci_slot); - return 2; /* card exist but is used */ - } - } - } - - /* no card found */ - return 1; -} - -/****************************************************************************/ -/* mark card as used */ -int pci_card_alloc(struct pcilst_struct *amcc, int master) -{ - int i; - - if (!amcc) - return -1; - - if (amcc->used) - return 1; - if (comedi_pci_enable(amcc->pcidev, "addi_amcc_s5933")) - return -1; - /* Resources will be accurate now. */ - for (i = 0; i < 5; i++) - amcc->io_addr[i] = pci_resource_start(amcc->pcidev, i); - if (master) - pci_set_master(amcc->pcidev); - amcc->used = 1; - - return 0; -} - -/****************************************************************************/ -/* mark card as free */ -int i_pci_card_free(struct pcilst_struct *amcc) -{ - if (!amcc) - return -1; - - if (!amcc->used) - return 1; - amcc->used = 0; - comedi_pci_disable(amcc->pcidev); - return 0; -} - -/****************************************************************************/ -/* display list of found cards */ -void v_pci_card_list_display(void) -{ - struct pcilst_struct *amcc, *next; - - printk(KERN_DEBUG "List of pci cards\n"); - printk(KERN_DEBUG "bus:slot:func vendor device io_amcc io_daq irq used\n"); - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - printk - ("%2d %2d %2d 0x%4x 0x%4x 0x%8llx 0x%8llx %2u %2d\n", - amcc->pci_bus, amcc->pci_slot, amcc->pci_func, - amcc->vendor, amcc->device, - (unsigned long long)amcc->io_addr[0], - (unsigned long long)amcc->io_addr[2], amcc->irq, - amcc->used); - - } -} - -/****************************************************************************/ -/* return all card information for driver */ -int i_pci_card_data(struct pcilst_struct *amcc, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, resource_size_t * io_addr, - unsigned int *irq) -{ - int i; - - if (!amcc) - return -1; - *pci_bus = amcc->pci_bus; - *pci_slot = amcc->pci_slot; - *pci_func = amcc->pci_func; - for (i = 0; i < 5; i++) - io_addr[i] = amcc->io_addr[i]; - *irq = amcc->irq; - return 0; -} - -/****************************************************************************/ -/* select and alloc card */ -struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - int i_Master) -{ - struct pcilst_struct *card; - - if ((pci_bus < 1) & (pci_slot < 1)) { - /* use autodetection */ - card = ptr_find_free_pci_card_by_device(vendor_id, device_id); - if (card == NULL) { - printk(" - Unused card not found in system!\n"); - return NULL; - } - } else { - switch (i_find_free_pci_card_by_position(vendor_id, device_id, - pci_bus, pci_slot, - &card)) { - case 1: - printk(" - Card not found on requested position b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - case 2: - printk(" - Card on requested position is used b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - } - } - - if (pci_card_alloc(card, i_Master) != 0) { - printk(" - Can't allocate card!\n"); - return NULL; - - } - - return card; -} -#endif diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index 6cf19ed683a..dc87df03220 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -11,13 +11,14 @@ Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. 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 free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 2 of the License, or (at your option) any later +version. -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the GNU General Public License for more details. @endverbatim */ @@ -29,2654 +30,78 @@ You should also find the complete GPL in the COPYING file accompanying this sour | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | +-----------------------------------------------------------------------+ - | Project : ADDI DATA | Compiler : GCC | + | Project : ADDI DATA | Compiler : GCC | | Modulname : addi_common.c | Version : 2.96 | +-------------------------------+---------------------------------------+ - | Author : | Date : | + | Author : | Date : | +-----------------------------------------------------------------------+ | Description : ADDI COMMON Main Module | +-----------------------------------------------------------------------+ - | CONFIG OPTIONS | - | option[0] - PCI bus number - if bus number and slot number are 0, | - | then driver search for first unused card | - | option[1] - PCI slot number | - | | - | option[2] = 0 - DMA ENABLE | - | = 1 - DMA DISABLE | - +----------+-----------+------------------------------------------------+ */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/mm.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/timex.h> -#include <linux/timer.h> -#include <linux/pci.h> -#include <linux/gfp.h> -#include "../../comedidev.h" -#include <asm/io.h> -#if defined(CONFIG_APCI_1710) || defined(CONFIG_APCI_3200) || defined(CONFIG_APCI_3300) -#include <asm/i387.h> -#endif -#include "../comedi_fc.h" - -#include "addi_common.h" -#include "addi_amcc_s5933.h" - -#ifndef ADDIDATA_DRIVER_NAME -#define ADDIDATA_DRIVER_NAME "addi_common" -#endif - -/* Update-0.7.57->0.7.68MODULE_AUTHOR("ADDI-DATA GmbH <info@addi-data.com>"); */ -/* Update-0.7.57->0.7.68MODULE_DESCRIPTION("Comedi ADDI-DATA module"); */ -/* Update-0.7.57->0.7.68MODULE_LICENSE("GPL"); */ - -#define devpriv ((struct addi_private *)dev->private) -#define this_board ((const struct addi_board *)dev->board_ptr) - -#if defined(CONFIG_APCI_1710) || defined(CONFIG_APCI_3200) || defined(CONFIG_APCI_3300) -/* BYTE b_SaveFPUReg [94]; */ - -void fpu_begin(void) -{ - /* asm ("fstenv b_SaveFPUReg"); */ - kernel_fpu_begin(); -} - -void fpu_end(void) +static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* asm ("frstor b_SaveFPUReg"); */ - kernel_fpu_end(); -} -#endif - -#include "addi_eeprom.c" -#if (defined (CONFIG_APCI_3120) || defined (CONFIG_APCI_3001)) -#include "hwdrv_apci3120.c" -#endif -#ifdef CONFIG_APCI_1032 -#include "hwdrv_apci1032.c" -#endif -#ifdef CONFIG_APCI_1516 -#include "hwdrv_apci1516.c" -#endif -#ifdef CONFIG_APCI_2016 -#include "hwdrv_apci2016.c" -#endif -#ifdef CONFIG_APCI_2032 -#include "hwdrv_apci2032.c" -#endif -#ifdef CONFIG_APCI_2200 -#include "hwdrv_apci2200.c" -#endif -#ifdef CONFIG_APCI_1564 -#include "hwdrv_apci1564.c" -#endif -#ifdef CONFIG_APCI_1500 -#include "hwdrv_apci1500.c" -#endif -#ifdef CONFIG_APCI_3501 -#include "hwdrv_apci3501.c" -#endif -#ifdef CONFIG_APCI_035 -#include "hwdrv_apci035.c" -#endif -#if (defined (CONFIG_APCI_3200) || defined (CONFIG_APCI_3300)) -#include "hwdrv_apci3200.c" -#endif -#ifdef CONFIG_APCI_1710 -#include "hwdrv_APCI1710.c" -#endif -#ifdef CONFIG_APCI_16XX -#include "hwdrv_apci16xx.c" -#endif -#ifdef CONFIG_APCI_3XXX -#include "hwdrv_apci3xxx.c" -#endif - -#ifndef COMEDI_SUBD_TTLIO -#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ -#endif - -static DEFINE_PCI_DEVICE_TABLE(addi_apci_tbl) = { -#ifdef CONFIG_APCI_3120 - {APCI3120_BOARD_VENDOR_ID, 0x818D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_1032 - {APCI1032_BOARD_VENDOR_ID, 0x1003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_1516 - {APCI1516_BOARD_VENDOR_ID, 0x1001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_2016 - {APCI2016_BOARD_VENDOR_ID, 0x1002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_2032 - {APCI2032_BOARD_VENDOR_ID, 0x1004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_2200 - {APCI2200_BOARD_VENDOR_ID, 0x1005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_1564 - {APCI1564_BOARD_VENDOR_ID, 0x1006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_1500 - {APCI1500_BOARD_VENDOR_ID, 0x80fc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_3001 - {APCI3120_BOARD_VENDOR_ID, 0x828D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_3501 - {APCI3501_BOARD_VENDOR_ID, 0x3001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_035 - {APCI035_BOARD_VENDOR_ID, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_3200 - {APCI3200_BOARD_VENDOR_ID, 0x3000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_3300 - {APCI3200_BOARD_VENDOR_ID, 0x3007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_1710 - {APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_16XX - {0x15B8, 0x1009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x100A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif -#ifdef CONFIG_APCI_3XXX - {0x15B8, 0x3010, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x300F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x300E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3013, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3014, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3015, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3016, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3017, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3018, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3019, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x301F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3020, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3023, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x300B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3004, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0x15B8, 0x3024, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, -#endif - {0} -}; - -MODULE_DEVICE_TABLE(pci, addi_apci_tbl); - -static const struct addi_board boardtypes[] = { -#ifdef CONFIG_APCI_3120 - {"apci3120", - APCI3120_BOARD_VENDOR_ID, - 0x818D, - AMCC_OP_REG_SIZE, - APCI3120_ADDRESS_RANGE, - 8, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 16, - 8, - 16, - 8, - 0xffff, - 0x3fff, - &range_apci3120_ai, - &range_apci3120_ao, - 4, - 4, - 0x0f, - 0, - NULL, - 1, - 1, - 1, - 10000, - 100000, - v_APCI3120_Interrupt, - i_APCI3120_Reset, - i_APCI3120_InsnConfigAnalogInput, - i_APCI3120_InsnReadAnalogInput, - NULL, - NULL, - i_APCI3120_CommandTestAnalogInput, - i_APCI3120_CommandAnalogInput, - i_APCI3120_StopCyclicAcquisition, - NULL, - i_APCI3120_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3120_InsnReadDigitalInput, - NULL, - i_APCI3120_InsnBitsDigitalInput, - i_APCI3120_InsnConfigDigitalOutput, - i_APCI3120_InsnWriteDigitalOutput, - i_APCI3120_InsnBitsDigitalOutput, - NULL, - i_APCI3120_InsnConfigTimer, - i_APCI3120_InsnWriteTimer, - i_APCI3120_InsnReadTimer, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_1032 - {"apci1032", - APCI1032_BOARD_VENDOR_ID, - 0x1003, - 4, - APCI1032_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_93C76, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 32, - 0, - 0, - 0, - NULL, - 0, - 0, - 0, - 0, - 0, - v_APCI1032_Interrupt, - i_APCI1032_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI1032_ConfigDigitalInput, - i_APCI1032_Read1DigitalInput, - NULL, - i_APCI1032_ReadMoreDigitalInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_1516 - {"apci1516", - APCI1516_BOARD_VENDOR_ID, - 0x1001, - 128, - APCI1516_ADDRESS_RANGE, - 32, - 0, - ADDIDATA_EEPROM, - ADDIDATA_S5920, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 8, - 8, - 0, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - NULL, - i_APCI1516_Reset, - NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI1516_Read1DigitalInput, - NULL, - i_APCI1516_ReadMoreDigitalInput, - i_APCI1516_ConfigDigitalOutput, - i_APCI1516_WriteDigitalOutput, - i_APCI1516_ReadDigitalOutput, - NULL, - i_APCI1516_ConfigWatchdog, - i_APCI1516_StartStopWriteWatchdog, - i_APCI1516_ReadWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_2016 - {"apci2016", - APCI2016_BOARD_VENDOR_ID, - 0x1002, - 128, - APCI2016_ADDRESS_RANGE, - 32, - 0, - ADDIDATA_EEPROM, - ADDIDATA_S5920, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 16, - 0, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - NULL, - i_APCI2016_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI2016_ConfigDigitalOutput, - i_APCI2016_WriteDigitalOutput, - i_APCI2016_BitsDigitalOutput, - NULL, - i_APCI2016_ConfigWatchdog, - i_APCI2016_StartStopWriteWatchdog, - i_APCI2016_ReadWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_2032 - {"apci2032", - APCI2032_BOARD_VENDOR_ID, - 0x1004, - 4, - APCI2032_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_93C76, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 32, - 0xffffffff, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - v_APCI2032_Interrupt, - i_APCI2032_Reset, - NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI2032_ConfigDigitalOutput, - i_APCI2032_WriteDigitalOutput, - i_APCI2032_ReadDigitalOutput, - i_APCI2032_ReadInterruptStatus, - i_APCI2032_ConfigWatchdog, - i_APCI2032_StartStopWriteWatchdog, - i_APCI2032_ReadWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_2200 - {"apci2200", - APCI2200_BOARD_VENDOR_ID, - 0x1005, - 4, - APCI2200_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_93C76, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 8, - 16, - 0, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - NULL, - i_APCI2200_Reset, - NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI2200_Read1DigitalInput, - NULL, - i_APCI2200_ReadMoreDigitalInput, - i_APCI2200_ConfigDigitalOutput, - i_APCI2200_WriteDigitalOutput, - i_APCI2200_ReadDigitalOutput, - NULL, - i_APCI2200_ConfigWatchdog, - i_APCI2200_StartStopWriteWatchdog, - i_APCI2200_ReadWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_1564 - {"apci1564", - APCI1564_BOARD_VENDOR_ID, - 0x1006, - 128, - APCI1564_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_93C76, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 32, - 32, - 0xffffffff, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - v_APCI1564_Interrupt, - i_APCI1564_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI1564_ConfigDigitalInput, - i_APCI1564_Read1DigitalInput, - NULL, - i_APCI1564_ReadMoreDigitalInput, - i_APCI1564_ConfigDigitalOutput, - i_APCI1564_WriteDigitalOutput, - i_APCI1564_ReadDigitalOutput, - i_APCI1564_ReadInterruptStatus, - i_APCI1564_ConfigTimerCounterWatchdog, - i_APCI1564_StartStopWriteTimerCounterWatchdog, - i_APCI1564_ReadTimerCounterWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_1500 - {"apci1500", - APCI1500_BOARD_VENDOR_ID, - 0x80fc, - 128, - APCI1500_ADDRESS_RANGE, - 4, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 16, - 16, - 0xffff, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - v_APCI1500_Interrupt, - i_APCI1500_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI1500_ConfigDigitalInputEvent, - i_APCI1500_Initialisation, - i_APCI1500_StartStopInputEvent, - i_APCI1500_ReadMoreDigitalInput, - i_APCI1500_ConfigDigitalOutputErrorInterrupt, - i_APCI1500_WriteDigitalOutput, - i_APCI1500_ConfigureInterrupt, - NULL, - i_APCI1500_ConfigCounterTimerWatchdog, - i_APCI1500_StartStopTriggerTimerCounterWatchdog, - i_APCI1500_ReadInterruptMask, - i_APCI1500_ReadCounterTimerWatchdog, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_3001 - {"apci3001", - APCI3120_BOARD_VENDOR_ID, - 0x828D, - AMCC_OP_REG_SIZE, - APCI3120_ADDRESS_RANGE, - 8, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 16, - 8, - 16, - 0, - 0xfff, - 0, - &range_apci3120_ai, - NULL, - 4, - 4, - 0x0f, - 0, - NULL, - 1, - 1, - 1, - 10000, - 100000, - v_APCI3120_Interrupt, - i_APCI3120_Reset, - i_APCI3120_InsnConfigAnalogInput, - i_APCI3120_InsnReadAnalogInput, - NULL, - NULL, - i_APCI3120_CommandTestAnalogInput, - i_APCI3120_CommandAnalogInput, - i_APCI3120_StopCyclicAcquisition, - NULL, - NULL, - NULL, - NULL, - i_APCI3120_InsnReadDigitalInput, - NULL, - i_APCI3120_InsnBitsDigitalInput, - i_APCI3120_InsnConfigDigitalOutput, - i_APCI3120_InsnWriteDigitalOutput, - i_APCI3120_InsnBitsDigitalOutput, - NULL, - i_APCI3120_InsnConfigTimer, - i_APCI3120_InsnWriteTimer, - i_APCI3120_InsnReadTimer, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_3501 - {"apci3501", - APCI3501_BOARD_VENDOR_ID, - 0x3001, - 64, - APCI3501_ADDRESS_RANGE, - 0, - 0, - ADDIDATA_EEPROM, - ADDIDATA_S5933, - 0, - 0, - 0, - 8, - 0, - 16383, - NULL, - &range_apci3501_ao, - 2, - 2, - 0x3, - 0, - NULL, - 0, - 1, - 0, - 0, - 0, - v_APCI3501_Interrupt, - i_APCI3501_Reset, - NULL, NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3501_ConfigAnalogOutput, - i_APCI3501_WriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3501_ReadDigitalInput, - i_APCI3501_ConfigDigitalOutput, - i_APCI3501_WriteDigitalOutput, - i_APCI3501_ReadDigitalOutput, - NULL, - i_APCI3501_ConfigTimerCounterWatchdog, - i_APCI3501_StartStopWriteTimerCounterWatchdog, - i_APCI3501_ReadTimerCounterWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_035 - {"apci035", - APCI035_BOARD_VENDOR_ID, - 0x0300, - 127, - APCI035_ADDRESS_RANGE, - 0, - 0, - 1, - ADDIDATA_S5920, - 16, - 8, - 16, - 0, - 0xff, - 0, - &range_apci035_ai, - NULL, - 0, - 0, - 0, - 0, - NULL, - 0, - 1, - 0, - 10000, - 100000, - v_APCI035_Interrupt, - i_APCI035_Reset, - i_APCI035_ConfigAnalogInput, - i_APCI035_ReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI035_ConfigTimerWatchdog, - i_APCI035_StartStopWriteTimerWatchdog, - i_APCI035_ReadTimerWatchdog, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_3200 - {"apci3200", - APCI3200_BOARD_VENDOR_ID, - 0x3000, - 128, - 256, - 4, - 4, - ADDIDATA_EEPROM, - ADDIDATA_S5920, - 16, - 8, - 16, - 0, - 0x3ffff, - 0, - &range_apci3200_ai, - NULL, - 4, - 4, - 0, - 0, - NULL, - 0, - 0, - 0, - 10000, - 100000, - v_APCI3200_Interrupt, - i_APCI3200_Reset, - i_APCI3200_ConfigAnalogInput, - i_APCI3200_ReadAnalogInput, - i_APCI3200_InsnWriteReleaseAnalogInput, - i_APCI3200_InsnBits_AnalogInput_Test, - i_APCI3200_CommandTestAnalogInput, - i_APCI3200_CommandAnalogInput, - i_APCI3200_StopCyclicAcquisition, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3200_ReadDigitalInput, - i_APCI3200_ConfigDigitalOutput, - i_APCI3200_WriteDigitalOutput, - i_APCI3200_ReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_3300 - /* Begin JK .20.10.2004 = APCI-3300 integration */ - {"apci3300", - APCI3200_BOARD_VENDOR_ID, - 0x3007, - 128, - 256, - 4, - 4, - ADDIDATA_EEPROM, - ADDIDATA_S5920, - 0, - 8, - 8, - 0, - 0x3ffff, - 0, - &range_apci3300_ai, - NULL, - 4, - 4, - 0, - 0, - NULL, - 0, - 0, - 0, - 10000, - 100000, - v_APCI3200_Interrupt, - i_APCI3200_Reset, - i_APCI3200_ConfigAnalogInput, - i_APCI3200_ReadAnalogInput, - i_APCI3200_InsnWriteReleaseAnalogInput, - i_APCI3200_InsnBits_AnalogInput_Test, - i_APCI3200_CommandTestAnalogInput, - i_APCI3200_CommandAnalogInput, - i_APCI3200_StopCyclicAcquisition, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3200_ReadDigitalInput, - i_APCI3200_ConfigDigitalOutput, - i_APCI3200_WriteDigitalOutput, - i_APCI3200_ReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_1710 - {"apci1710", APCI1710_BOARD_VENDOR_ID, APCI1710_BOARD_DEVICE_ID, - 128, - 8, - 256, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 0, - 0, - 0, - NULL, - 0, - 0, - 0, - 0, - 0, - v_APCI1710_Interrupt, - i_APCI1710_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, -#endif -#ifdef CONFIG_APCI_16XX - {"apci1648", - 0x15B8, - 0x1009, - 128, - 0, - 0, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 0, - 0, - 48, - &range_apci16xx_ttl, - 0, - 0, - 0, - 0, - 0, - NULL, - i_APCI16XX_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI16XX_InsnConfigInitTTLIO, - i_APCI16XX_InsnBitsReadTTLIO, - i_APCI16XX_InsnReadTTLIOAllPortValue, - i_APCI16XX_InsnBitsWriteTTLIO}, - - {"apci1696", - 0x15B8, - 0x100A, - 128, - 0, - 0, - 0, - ADDIDATA_NO_EEPROM, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - NULL, - NULL, - 0, - 0, - 0, - 96, - &range_apci16xx_ttl, - 0, - 0, - 0, - 0, - 0, - NULL, - i_APCI16XX_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI16XX_InsnConfigInitTTLIO, - i_APCI16XX_InsnBitsReadTTLIO, - i_APCI16XX_InsnReadTTLIOAllPortValue, - i_APCI16XX_InsnBitsWriteTTLIO}, -#endif -#ifdef CONFIG_APCI_3XXX - {"apci3000-16", - 0x15B8, - 0x3010, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3000-8", - 0x15B8, - 0x300F, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3000-4", - 0x15B8, - 0x300E, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 4, - 2, - 4, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3006-16", - 0x15B8, - 0x3013, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3006-8", - 0x15B8, - 0x3014, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3006-4", - 0x15B8, - 0x3015, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 4, - 2, - 4, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3010-16", - 0x15B8, - 0x3016, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3010-8", - 0x15B8, - 0x3017, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3010-4", - 0x15B8, - 0x3018, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 4, - 2, - 4, - 0, - 4095, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3016-16", - 0x15B8, - 0x3019, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3016-8", - 0x15B8, - 0x301A, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3016-4", - 0x15B8, - 0x301B, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 4, - 2, - 4, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3100-16-4", - 0x15B8, - 0x301C, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 4, - 4095, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3100-8-4", - 0x15B8, - 0x301D, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 4, - 4095, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3106-16-4", - 0x15B8, - 0x301E, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 4, - 65535, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3106-8-4", - 0x15B8, - 0x301F, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 4, - 65535, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 10000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3110-16-4", - 0x15B8, - 0x3020, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 4, - 4095, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3110-8-4", - 0x15B8, - 0x3021, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 4, - 4095, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3116-16-4", - 0x15B8, - 0x3022, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 16, - 8, - 16, - 4, - 65535, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3116-8-4", - 0x15B8, - 0x3023, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 8, - 4, - 8, - 4, - 65535, - 4095, - &range_apci3XXX_ai, - &range_apci3XXX_ao, - 4, - 4, - 1, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, - - {"apci3003", - 0x15B8, - 0x300B, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 4, - 4, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 0, - NULL, - 0, - 0, - 7, - 2500, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, - - {"apci3002-16", - 0x15B8, - 0x3002, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 16, - 16, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 0, - NULL, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, - - {"apci3002-8", - 0x15B8, - 0x3003, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 8, - 8, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 0, - NULL, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, - - {"apci3002-4", - 0x15B8, - 0x3004, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 4, - 4, - 0, - 65535, - 0, - &range_apci3XXX_ai, - NULL, - 4, - 4, - 1, - 0, - NULL, - 0, - 0, - 6, - 5000, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - i_APCI3XXX_InsnConfigAnalogInput, - i_APCI3XXX_InsnReadAnalogInput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnReadDigitalInput, - NULL, - i_APCI3XXX_InsnBitsDigitalInput, - NULL, - i_APCI3XXX_InsnWriteDigitalOutput, - i_APCI3XXX_InsnBitsDigitalOutput, - i_APCI3XXX_InsnReadDigitalOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, - - {"apci3500", - 0x15B8, - 0x3024, - 256, - 256, - 256, - 256, - ADDIDATA_NO_EEPROM, - ADDIDATA_9054, - 0, - 0, - 0, - 4, - 0, - 4095, - NULL, - &range_apci3XXX_ao, - 0, - 0, - 0, - 24, - &range_apci3XXX_ttl, - 0, - 0, - 0, - 0, - 0, - v_APCI3XXX_Interrupt, - i_APCI3XXX_Reset, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnWriteAnalogOutput, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - i_APCI3XXX_InsnConfigInitTTLIO, - i_APCI3XXX_InsnBitsTTLIO, - i_APCI3XXX_InsnReadTTLIO, - i_APCI3XXX_InsnWriteTTLIO}, -#endif -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct addi_board)) - -static struct comedi_driver driver_addi = { - .driver_name = ADDIDATA_DRIVER_NAME, - .module = THIS_MODULE, - .attach = i_ADDI_Attach, - .detach = i_ADDI_Detach, - .num_names = n_boardtypes, - .board_name = &boardtypes[0].pc_DriverName, - .offset = sizeof(struct addi_board), -}; + const struct addi_board *this_board = comedi_board(dev); + struct addi_private *devpriv = dev->private; + unsigned short w_Address = CR_CHAN(insn->chanspec); + unsigned short w_Data; -static int __devinit driver_addi_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_addi.driver_name); -} + w_Data = addi_eeprom_readw(devpriv->i_IobaseAmcc, + this_board->pc_EepromChip, 2 * w_Address); + data[0] = w_Data; -static void __devexit driver_addi_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); + return insn->n; } -static struct pci_driver driver_addi_pci_driver = { - .id_table = addi_apci_tbl, - .probe = &driver_addi_pci_probe, - .remove = __devexit_p(&driver_addi_pci_remove) -}; - -static int __init driver_addi_init_module(void) +static irqreturn_t v_ADDI_Interrupt(int irq, void *d) { - int retval; - - retval = comedi_driver_register(&driver_addi); - if (retval < 0) - return retval; + struct comedi_device *dev = d; + const struct addi_board *this_board = comedi_board(dev); - driver_addi_pci_driver.name = (char *)driver_addi.driver_name; - return pci_register_driver(&driver_addi_pci_driver); + this_board->interrupt(irq, d); + return IRQ_RETVAL(1); } -static void __exit driver_addi_cleanup_module(void) +static int i_ADDI_Reset(struct comedi_device *dev) { - pci_unregister_driver(&driver_addi_pci_driver); - comedi_driver_unregister(&driver_addi); -} - -module_init(driver_addi_init_module); -module_exit(driver_addi_cleanup_module); + const struct addi_board *this_board = comedi_board(dev); -/* -+----------------------------------------------------------------------------+ -| Function name :static int i_ADDI_Attach(struct comedi_device *dev, | -| struct comedi_devconfig *it) | -| | -+----------------------------------------------------------------------------+ -| Task :Detects the card. | -| Configure the driver for a particular board. | -| This function does all the initializations and memory | -| allocation of data structures for the driver. | -+----------------------------------------------------------------------------+ -| Input Parameters :struct comedi_device *dev | -| struct comedi_devconfig *it | -| | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -| | -+----------------------------------------------------------------------------+ -*/ + this_board->reset(dev); + return 0; +} -static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) +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); + struct addi_private *devpriv; struct comedi_subdevice *s; - int ret, pages, i, n_subdevices; + int ret, n_subdevices; unsigned int dw_Dummy; - resource_size_t io_addr[5]; - unsigned int irq; - resource_size_t iobase_a, iobase_main, iobase_addon, iobase_reserved; - struct pcilst_struct *card = NULL; - unsigned char pci_bus, pci_slot, pci_func; - int i_Dma = 0; - - ret = alloc_private(dev, sizeof(struct addi_private)); - if (ret < 0) - return -ENOMEM; - - if (!pci_list_builded) { - v_pci_card_list_init(this_board->i_VendorId, 1); /* 1 for displaying the list.. */ - pci_list_builded = 1; - } - /* printk("comedi%d: "ADDIDATA_DRIVER_NAME": board=%s",dev->minor,this_board->pc_DriverName); */ - - if ((this_board->i_Dma) && (it->options[2] == 0)) { - i_Dma = 1; - } - - card = ptr_select_and_alloc_pci_card(this_board->i_VendorId, - this_board->i_DeviceId, - it->options[0], - it->options[1], i_Dma); - if (card == NULL) - return -EIO; + dev->board_name = this_board->pc_DriverName; - devpriv->allocated = 1; - - if ((i_pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0], - &irq)) < 0) { - i_pci_card_free(card); - printk(" - Can't get AMCC data!\n"); - return -EIO; - } + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - iobase_a = io_addr[0]; - iobase_main = io_addr[1]; - iobase_addon = io_addr[2]; - iobase_reserved = io_addr[3]; - printk("\nBus %d: Slot %d: Funct%d\nBase0: 0x%8llx\nBase1: 0x%8llx\nBase2: 0x%8llx\nBase3: 0x%8llx\n", pci_bus, pci_slot, pci_func, (unsigned long long)io_addr[0], (unsigned long long)io_addr[1], (unsigned long long)io_addr[2], (unsigned long long)io_addr[3]); + ret = comedi_pci_enable(dev); + if (ret) + return ret; - if ((this_board->pc_EepromChip == NULL) - || (strcmp(this_board->pc_EepromChip, ADDIDATA_9054) != 0)) { - /************************************/ - /* Test if more that 1 address used */ - /************************************/ + if (this_board->i_IorangeBase1) + dev->iobase = pci_resource_start(pcidev, 1); + else + dev->iobase = pci_resource_start(pcidev, 0); - if (this_board->i_IorangeBase1 != 0) { - dev->iobase = (unsigned long)iobase_main; /* DAQ base address... */ - } else { - dev->iobase = (unsigned long)iobase_a; /* DAQ base address... */ - } - - dev->board_name = this_board->pc_DriverName; - devpriv->amcc = card; - devpriv->iobase = (int) dev->iobase; - devpriv->i_IobaseAmcc = (int) iobase_a; /* AMCC base address... */ - devpriv->i_IobaseAddon = (int) iobase_addon; /* ADD ON base address.... */ - devpriv->i_IobaseReserved = (int) iobase_reserved; - } else { - dev->board_name = this_board->pc_DriverName; - dev->iobase = (unsigned long)io_addr[2]; - devpriv->amcc = card; - devpriv->iobase = (int) io_addr[2]; - devpriv->i_IobaseReserved = (int) io_addr[3]; - printk("\nioremap begin"); - devpriv->dw_AiBase = ioremap(io_addr[3], - this_board->i_IorangeBase3); - printk("\nioremap end"); - } + devpriv->iobase = dev->iobase; + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); + devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); /* Initialize parameters that can be overridden in EEPROM */ devpriv->s_EeParameters.i_NbrAiChannel = this_board->i_NbrAiChannel; @@ -2686,7 +111,6 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->s_EeParameters.i_NbrDiChannel = this_board->i_NbrDiChannel; devpriv->s_EeParameters.i_NbrDoChannel = this_board->i_NbrDoChannel; devpriv->s_EeParameters.i_DoMaxdata = this_board->i_DoMaxdata; - devpriv->s_EeParameters.i_Dma = this_board->i_Dma; devpriv->s_EeParameters.i_Timer = this_board->i_Timer; devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = this_board->ui_MinAcquisitiontimeNs; @@ -2695,415 +119,166 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) /* ## */ - if (irq > 0) { - if (request_irq(irq, v_ADDI_Interrupt, IRQF_SHARED, - this_board->pc_DriverName, dev) < 0) { - printk(", unable to allocate IRQ %u, DISABLING IT", - irq); - irq = 0; /* Can't use IRQ */ - } else { - printk("\nirq=%u", irq); - } - } else { - printk(", IRQ disabled"); + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; } - printk("\nOption %d %d %d\n", it->options[0], it->options[1], - it->options[2]); - dev->irq = irq; - /* Read eepeom and fill addi_board Structure */ if (this_board->i_PCIEeprom) { - printk("\nPCI Eeprom used"); if (!(strcmp(this_board->pc_EepromChip, "S5920"))) { /* Set 3 wait stait */ - if (!(strcmp(this_board->pc_DriverName, "apci035"))) { + if (!(strcmp(dev->board_name, "apci035"))) outl(0x80808082, devpriv->i_IobaseAmcc + 0x60); - } else { + else outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); - } + /* Enable the interrupt for the controller */ dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); - printk("\nEnable the interrupt for the controller"); } - printk("\nRead Eeprom"); - i_EepromReadMainHeader(io_addr[0], this_board->pc_EepromChip, - dev); - } else { - printk("\nPCI Eeprom unused"); - } - - if (it->options[2] > 0) { - devpriv->us_UseDma = ADDI_DISABLE; - } else { - devpriv->us_UseDma = ADDI_ENABLE; + addi_eeprom_read_info(dev, pci_resource_start(pcidev, 0)); } - if (devpriv->s_EeParameters.i_Dma) { - printk("\nDMA used"); - if (devpriv->us_UseDma == ADDI_ENABLE) { - /* alloc DMA buffers */ - devpriv->b_DmaDoubleBuffer = 0; - for (i = 0; i < 2; i++) { - for (pages = 4; pages >= 0; pages--) { - devpriv->ul_DmaBufferVirtual[i] = - (void *) __get_free_pages(GFP_KERNEL, pages); - - if (devpriv->ul_DmaBufferVirtual[i]) - break; - } - if (devpriv->ul_DmaBufferVirtual[i]) { - devpriv->ui_DmaBufferPages[i] = pages; - devpriv->ui_DmaBufferSize[i] = - PAGE_SIZE * pages; - devpriv->ui_DmaBufferSamples[i] = - devpriv-> - ui_DmaBufferSize[i] >> 1; - devpriv->ul_DmaBufferHw[i] = - virt_to_bus((void *)devpriv-> - ul_DmaBufferVirtual[i]); - } - } - if (!devpriv->ul_DmaBufferVirtual[0]) { - printk - (", Can't allocate DMA buffer, DMA disabled!"); - devpriv->us_UseDma = ADDI_DISABLE; - } - - if (devpriv->ul_DmaBufferVirtual[1]) { - devpriv->b_DmaDoubleBuffer = 1; - } - } - - if ((devpriv->us_UseDma == ADDI_ENABLE)) { - printk("\nDMA ENABLED\n"); + n_subdevices = 7; + ret = comedi_alloc_subdevices(dev, n_subdevices); + if (ret) + return ret; + + /* Allocate and Initialise AI Subdevice Structures */ + s = &dev->subdevices[0]; + if ((devpriv->s_EeParameters.i_NbrAiChannel) + || (this_board->i_NbrAiChannelDiff)) { + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = + SDF_READABLE | SDF_COMMON | SDF_GROUND + | SDF_DIFF; + if (devpriv->s_EeParameters.i_NbrAiChannel) { + s->n_chan = + devpriv->s_EeParameters.i_NbrAiChannel; + devpriv->b_SingelDiff = 0; } else { - printk("\nDMA DISABLED\n"); + s->n_chan = this_board->i_NbrAiChannelDiff; + devpriv->b_SingelDiff = 1; } - } - - if (!strcmp(this_board->pc_DriverName, "apci1710")) { -#ifdef CONFIG_APCI_1710 - i_ADDI_AttachPCI1710(dev); + s->maxdata = devpriv->s_EeParameters.i_AiMaxdata; + s->len_chanlist = this_board->i_AiChannelList; + s->range_table = this_board->pr_AiRangelist; + + s->insn_config = this_board->ai_config; + s->insn_read = this_board->ai_read; + s->insn_write = this_board->ai_write; + s->insn_bits = this_board->ai_bits; + s->do_cmdtest = this_board->ai_cmdtest; + s->do_cmd = this_board->ai_cmd; + s->cancel = this_board->ai_cancel; - /* save base address */ - devpriv->s_BoardInfos.ui_Address = io_addr[2]; -#endif } else { - /* Update-0.7.57->0.7.68dev->n_subdevices = 7; */ - n_subdevices = 7; - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) - return ret; - - /* Allocate and Initialise AI Subdevice Structures */ - s = dev->subdevices + 0; - if ((devpriv->s_EeParameters.i_NbrAiChannel) - || (this_board->i_NbrAiChannelDiff)) { - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_COMMON | SDF_GROUND - | SDF_DIFF; - if (devpriv->s_EeParameters.i_NbrAiChannel) { - s->n_chan = - devpriv->s_EeParameters.i_NbrAiChannel; - devpriv->b_SingelDiff = 0; - } else { - s->n_chan = this_board->i_NbrAiChannelDiff; - devpriv->b_SingelDiff = 1; - } - s->maxdata = devpriv->s_EeParameters.i_AiMaxdata; - s->len_chanlist = this_board->i_AiChannelList; - s->range_table = this_board->pr_AiRangelist; - - /* Set the initialisation flag */ - devpriv->b_AiInitialisation = 1; - - s->insn_config = - this_board->i_hwdrv_InsnConfigAnalogInput; - s->insn_read = this_board->i_hwdrv_InsnReadAnalogInput; - s->insn_write = - this_board->i_hwdrv_InsnWriteAnalogInput; - s->insn_bits = this_board->i_hwdrv_InsnBitsAnalogInput; - s->do_cmdtest = - this_board->i_hwdrv_CommandTestAnalogInput; - s->do_cmd = this_board->i_hwdrv_CommandAnalogInput; - s->cancel = this_board->i_hwdrv_CancelAnalogInput; - - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /* Allocate and Initialise AO Subdevice Structures */ - s = dev->subdevices + 1; - if (devpriv->s_EeParameters.i_NbrAoChannel) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = devpriv->s_EeParameters.i_NbrAoChannel; - s->maxdata = devpriv->s_EeParameters.i_AoMaxdata; - s->len_chanlist = - devpriv->s_EeParameters.i_NbrAoChannel; - s->range_table = this_board->pr_AoRangelist; - s->insn_config = - this_board->i_hwdrv_InsnConfigAnalogOutput; - s->insn_write = - this_board->i_hwdrv_InsnWriteAnalogOutput; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - /* Allocate and Initialise DI Subdevice Structures */ - s = dev->subdevices + 2; - if (devpriv->s_EeParameters.i_NbrDiChannel) { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = devpriv->s_EeParameters.i_NbrDiChannel; - s->maxdata = 1; - s->len_chanlist = - devpriv->s_EeParameters.i_NbrDiChannel; - s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ - s->insn_config = - this_board->i_hwdrv_InsnConfigDigitalInput; - s->insn_read = this_board->i_hwdrv_InsnReadDigitalInput; - s->insn_write = - this_board->i_hwdrv_InsnWriteDigitalInput; - s->insn_bits = this_board->i_hwdrv_InsnBitsDigitalInput; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - /* Allocate and Initialise DO Subdevice Structures */ - s = dev->subdevices + 3; - if (devpriv->s_EeParameters.i_NbrDoChannel) { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = devpriv->s_EeParameters.i_NbrDoChannel; - s->maxdata = devpriv->s_EeParameters.i_DoMaxdata; - s->len_chanlist = - devpriv->s_EeParameters.i_NbrDoChannel; - s->range_table = &range_digital; - s->io_bits = 0xf; /* all bits output */ - - s->insn_config = this_board->i_hwdrv_InsnConfigDigitalOutput; /* for digital output memory.. */ - s->insn_write = - this_board->i_hwdrv_InsnWriteDigitalOutput; - s->insn_bits = - this_board->i_hwdrv_InsnBitsDigitalOutput; - s->insn_read = - this_board->i_hwdrv_InsnReadDigitalOutput; - } else { - s->type = COMEDI_SUBD_UNUSED; - } + s->type = COMEDI_SUBD_UNUSED; + } - /* Allocate and Initialise Timer Subdevice Structures */ - s = dev->subdevices + 4; - if (devpriv->s_EeParameters.i_Timer) { - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 1; - s->maxdata = 0; - s->len_chanlist = 1; - s->range_table = &range_digital; + /* Allocate and Initialise AO Subdevice Structures */ + s = &dev->subdevices[1]; + if (devpriv->s_EeParameters.i_NbrAoChannel) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = devpriv->s_EeParameters.i_NbrAoChannel; + s->maxdata = devpriv->s_EeParameters.i_AoMaxdata; + s->len_chanlist = + devpriv->s_EeParameters.i_NbrAoChannel; + s->insn_write = this_board->ao_write; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + /* Allocate and Initialise DI Subdevice Structures */ + s = &dev->subdevices[2]; + if (devpriv->s_EeParameters.i_NbrDiChannel) { + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = devpriv->s_EeParameters.i_NbrDiChannel; + s->maxdata = 1; + s->len_chanlist = + devpriv->s_EeParameters.i_NbrDiChannel; + s->range_table = &range_digital; + s->insn_config = this_board->di_config; + s->insn_read = this_board->di_read; + s->insn_write = this_board->di_write; + s->insn_bits = this_board->di_bits; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + /* Allocate and Initialise DO Subdevice Structures */ + s = &dev->subdevices[3]; + if (devpriv->s_EeParameters.i_NbrDoChannel) { + s->type = COMEDI_SUBD_DO; + s->subdev_flags = + SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = devpriv->s_EeParameters.i_NbrDoChannel; + s->maxdata = devpriv->s_EeParameters.i_DoMaxdata; + s->len_chanlist = + devpriv->s_EeParameters.i_NbrDoChannel; + s->range_table = &range_digital; + + /* insn_config - for digital output memory */ + s->insn_config = this_board->do_config; + s->insn_write = this_board->do_write; + s->insn_bits = this_board->do_bits; + s->insn_read = this_board->do_read; + } else { + s->type = COMEDI_SUBD_UNUSED; + } - s->insn_write = this_board->i_hwdrv_InsnWriteTimer; - s->insn_read = this_board->i_hwdrv_InsnReadTimer; - s->insn_config = this_board->i_hwdrv_InsnConfigTimer; - s->insn_bits = this_board->i_hwdrv_InsnBitsTimer; - } else { - s->type = COMEDI_SUBD_UNUSED; - } + /* Allocate and Initialise Timer Subdevice Structures */ + s = &dev->subdevices[4]; + if (devpriv->s_EeParameters.i_Timer) { + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + + s->insn_write = this_board->timer_write; + s->insn_read = this_board->timer_read; + s->insn_config = this_board->timer_config; + s->insn_bits = this_board->timer_bits; + } else { + s->type = COMEDI_SUBD_UNUSED; + } - /* Allocate and Initialise TTL */ - s = dev->subdevices + 5; - if (this_board->i_NbrTTLChannel) { - s->type = COMEDI_SUBD_TTLIO; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->i_NbrTTLChannel; - s->maxdata = 1; - s->io_bits = 0; /* all bits input */ - s->len_chanlist = this_board->i_NbrTTLChannel; - s->range_table = &range_digital; - s->insn_config = this_board->i_hwdr_ConfigInitTTLIO; - s->insn_bits = this_board->i_hwdr_ReadTTLIOBits; - s->insn_read = this_board->i_hwdr_ReadTTLIOAllPortValue; - s->insn_write = this_board->i_hwdr_WriteTTLIOChlOnOff; - } else { - s->type = COMEDI_SUBD_UNUSED; - } + /* Allocate and Initialise TTL */ + s = &dev->subdevices[5]; + s->type = COMEDI_SUBD_UNUSED; - /* EEPROM */ - s = dev->subdevices + 6; - if (this_board->i_PCIEeprom) { - s->type = COMEDI_SUBD_MEMORY; - s->subdev_flags = SDF_READABLE | SDF_INTERNAL; - s->n_chan = 256; - s->maxdata = 0xffff; - s->insn_read = i_ADDIDATA_InsnReadEeprom; - } else { - s->type = COMEDI_SUBD_UNUSED; - } + /* EEPROM */ + s = &dev->subdevices[6]; + if (this_board->i_PCIEeprom) { + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE | SDF_INTERNAL; + s->n_chan = 256; + s->maxdata = 0xffff; + s->insn_read = i_ADDIDATA_InsnReadEeprom; + } else { + s->type = COMEDI_SUBD_UNUSED; } - printk("\ni_ADDI_Attach end\n"); i_ADDI_Reset(dev); - devpriv->b_ValidDriver = 1; return 0; } -/* -+----------------------------------------------------------------------------+ -| Function name : static int i_ADDI_Detach(struct comedi_device *dev) | -| | -| | -+----------------------------------------------------------------------------+ -| Task : Deallocates resources of the addi_common driver | -| Free the DMA buffers, unregister irq. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_ADDI_Detach(struct comedi_device *dev) +static void i_ADDI_Detach(struct comedi_device *dev) { + struct addi_private *devpriv = dev->private; - if (dev->private) { - if (devpriv->b_ValidDriver) { + if (devpriv) { + if (dev->iobase) i_ADDI_Reset(dev); - } - - if (dev->irq) { + if (dev->irq) free_irq(dev->irq, dev); - } - - if ((this_board->pc_EepromChip == NULL) - || (strcmp(this_board->pc_EepromChip, - ADDIDATA_9054) != 0)) { - if (devpriv->allocated) { - i_pci_card_free(devpriv->amcc); - } - - 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]); - } - } else { - iounmap(devpriv->dw_AiBase); - - if (devpriv->allocated) { - i_pci_card_free(devpriv->amcc); - } - } - - if (pci_list_builded) { - /* v_pci_card_list_cleanup(PCI_VENDOR_ID_AMCC); */ - v_pci_card_list_cleanup(this_board->i_VendorId); - pci_list_builded = 0; - } } - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function name : static int i_ADDI_Reset(struct comedi_device *dev) | -| | -+----------------------------------------------------------------------------+ -| Task : Disables all interrupts, Resets digital output to low, | -| Set all analog output to low | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_ADDI_Reset(struct comedi_device *dev) -{ - - this_board->i_hwdrv_Reset(dev); - return 0; -} - -/* Interrupt function */ -/* -+----------------------------------------------------------------------------+ -| Function name : | -|static void v_ADDI_Interrupt(int irq, void *d) | -| | -+----------------------------------------------------------------------------+ -| Task : Registerd interrupt routine | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static irqreturn_t v_ADDI_Interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - this_board->v_hwdrv_Interrupt(irq, d); - return IRQ_RETVAL(1); -} - -/* EEPROM Read Function */ -/* -+----------------------------------------------------------------------------+ -| Function name : | -|INT i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) -| | -+----------------------------------------------------------------------------+ -| Task : Read 256 words from EEPROM | -| | -+----------------------------------------------------------------------------+ -| Input Parameters :(struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data) | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned short w_Data; - unsigned short w_Address; - w_Address = CR_CHAN(insn->chanspec); /* address to be read as 0,1,2,3...255 */ - - w_Data = w_EepromReadWord(devpriv->i_IobaseAmcc, - this_board->pc_EepromChip, 0x100 + (2 * w_Address)); - data[0] = w_Data; - /* multiplied by 2 bcozinput will be like 0,1,2...255 */ - return insn->n; - + comedi_pci_disable(dev); } diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.h b/drivers/staging/comedi/drivers/addi-data/addi_common.h index c6980b7dfea..5c6a11c35de 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.h +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.h @@ -15,33 +15,11 @@ * any later version. */ -#include <linux/kernel.h> -#include <linux/module.h> #include <linux/sched.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/timex.h> -#include <linux/timer.h> -#include <linux/pci.h> -#include <linux/io.h> -#include <linux/kmod.h> -#include <linux/uaccess.h> -#include "../../comedidev.h" -#include "addi_amcc_s5933.h" -#define ERROR -1 -#define SUCCESS 1 - -#define LOBYTE(W) (unsigned char)((W) & 0xFF) -#define HIBYTE(W) (unsigned char)(((W) >> 8) & 0xFF) -#define MAKEWORD(H, L) (unsigned short)((L) | ((H) << 8)) #define LOWORD(W) (unsigned short)((W) & 0xFFFF) #define HIWORD(W) (unsigned short)(((W) >> 16) & 0xFFFF) -#define MAKEDWORD(H, L) (unsigned int)((L) | ((H) << 16)) #define ADDI_ENABLE 1 #define ADDI_DISABLE 0 @@ -51,8 +29,6 @@ #define ADDIDATA_NO_EEPROM 0 #define ADDIDATA_93C76 "93C76" #define ADDIDATA_S5920 "S5920" -#define ADDIDATA_S5933 "S5933" -#define ADDIDATA_9054 "9054" /* ADDIDATA Enable Disable */ #define ADDIDATA_ENABLE 1 @@ -63,12 +39,7 @@ /* structure for the boardtype */ struct addi_board { const char *pc_DriverName; /* driver name */ - int i_VendorId; /* PCI vendor a device ID of card */ - int i_DeviceId; - int i_IorangeBase0; int i_IorangeBase1; - int i_IorangeBase2; /* base 2 range */ - int i_IorangeBase3; /* base 3 range */ int i_PCIEeprom; /* eeprom present or not */ char *pc_EepromChip; /* type of chip */ int i_NbrAiChannel; /* num of A/D chans */ @@ -78,361 +49,104 @@ struct addi_board { int i_AiMaxdata; /* resolution of A/D */ int i_AoMaxdata; /* resolution of D/A */ const struct comedi_lrange *pr_AiRangelist; /* rangelist for A/D */ - const struct comedi_lrange *pr_AoRangelist; /* rangelist for D/A */ int i_NbrDiChannel; /* Number of DI channels */ int i_NbrDoChannel; /* Number of DO channels */ int i_DoMaxdata; /* data to set all channels high */ - int i_NbrTTLChannel; /* Number of TTL channels */ - const struct comedi_lrange *pr_TTLRangelist; /* rangelist for TTL */ - - int i_Dma; /* dma present or not */ int i_Timer; /* timer subdevice present or not */ - unsigned char b_AvailableConvertUnit; unsigned int ui_MinAcquisitiontimeNs; /* Minimum Acquisition in Nano secs */ unsigned int ui_MinDelaytimeNs; /* Minimum Delay in Nano secs */ /* interrupt and reset */ - void (*v_hwdrv_Interrupt)(int irq, void *d); - int (*i_hwdrv_Reset)(struct comedi_device *dev); + void (*interrupt)(int irq, void *d); + int (*reset)(struct comedi_device *); /* Subdevice functions */ /* ANALOG INPUT */ - int (*i_hwdrv_InsnConfigAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnReadAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnWriteAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnBitsAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_CommandTestAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - int (*i_hwdrv_CommandAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s); - int (*i_hwdrv_CancelAnalogInput)(struct comedi_device *dev, - struct comedi_subdevice *s); + int (*ai_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ai_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ai_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ai_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*ai_cmdtest)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_cmd *); + int (*ai_cmd)(struct comedi_device *, struct comedi_subdevice *); + int (*ai_cancel)(struct comedi_device *, struct comedi_subdevice *); /* Analog Output */ - int (*i_hwdrv_InsnConfigAnalogOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnWriteAnalogOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnBitsAnalogOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + int (*ao_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); /* Digital Input */ - int (*i_hwdrv_InsnConfigDigitalInput) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnReadDigitalInput) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnWriteDigitalInput) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnBitsDigitalInput) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + int (*di_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*di_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*di_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*di_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); /* Digital Output */ - int (*i_hwdrv_InsnConfigDigitalOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnWriteDigitalOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnBitsDigitalOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnReadDigitalOutput)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + int (*do_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*do_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*do_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*do_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); /* TIMER */ - int (*i_hwdrv_InsnConfigTimer)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - int (*i_hwdrv_InsnWriteTimer)(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdrv_InsnReadTimer)(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - int (*i_hwdrv_InsnBitsTimer)(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - - /* TTL IO */ - int (*i_hwdr_ConfigInitTTLIO)(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdr_ReadTTLIOBits)(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - int (*i_hwdr_ReadTTLIOAllPortValue)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*i_hwdr_WriteTTLIOChlOnOff)(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -}; - -/* MODULE INFO STRUCTURE */ - -union str_ModuleInfo { - /* Incremental counter infos */ - struct { - union { - struct { - unsigned char b_ModeRegister1; - unsigned char b_ModeRegister2; - unsigned char b_ModeRegister3; - unsigned char b_ModeRegister4; - } s_ByteModeRegister; - unsigned int dw_ModeRegister1_2_3_4; - } s_ModeRegister; - - struct { - unsigned int b_IndexInit:1; - unsigned int b_CounterInit:1; - unsigned int b_ReferenceInit:1; - unsigned int b_IndexInterruptOccur:1; - unsigned int b_CompareLogicInit:1; - unsigned int b_FrequencyMeasurementInit:1; - unsigned int b_FrequencyMeasurementEnable:1; - } s_InitFlag; - - } s_SiemensCounterInfo; - - /* SSI infos */ - struct { - unsigned char b_SSIProfile; - unsigned char b_PositionTurnLength; - unsigned char b_TurnCptLength; - unsigned char b_SSIInit; - } s_SSICounterInfo; - - /* TTL I/O infos */ - struct { - unsigned char b_TTLInit; - unsigned char b_PortConfiguration[4]; - } s_TTLIOInfo; - - /* Digital I/O infos */ - struct { - unsigned char b_DigitalInit; - unsigned char b_ChannelAMode; - unsigned char b_ChannelBMode; - unsigned char b_OutputMemoryEnabled; - unsigned int dw_OutputMemory; - } s_DigitalIOInfo; - - /*********************/ - /* 82X54 timer infos */ - /*********************/ - - struct { - struct { - unsigned char b_82X54Init; - unsigned char b_InputClockSelection; - unsigned char b_InputClockLevel; - unsigned char b_OutputLevel; - unsigned char b_HardwareGateLevel; - unsigned int dw_ConfigurationWord; - } s_82X54TimerInfo[3]; - unsigned char b_InterruptMask; - } s_82X54ModuleInfo; - - /*********************/ - /* Chronometer infos */ - /*********************/ - - struct { - unsigned char b_ChronoInit; - unsigned char b_InterruptMask; - unsigned char b_PCIInputClock; - unsigned char b_TimingUnit; - unsigned char b_CycleMode; - double d_TimingInterval; - unsigned int dw_ConfigReg; - } s_ChronoModuleInfo; - - /***********************/ - /* Pulse encoder infos */ - /***********************/ - - struct { - struct { - unsigned char b_PulseEncoderInit; - } s_PulseEncoderInfo[4]; - unsigned int dw_SetRegister; - unsigned int dw_ControlRegister; - unsigned int dw_StatusRegister; - } s_PulseEncoderModuleInfo; - - /* Tor conter infos */ - struct { - struct { - unsigned char b_TorCounterInit; - unsigned char b_TimingUnit; - unsigned char b_InterruptEnable; - double d_TimingInterval; - unsigned int ul_RealTimingInterval; - } s_TorCounterInfo[2]; - unsigned char b_PCIInputClock; - } s_TorCounterModuleInfo; - - /* PWM infos */ - struct { - struct { - unsigned char b_PWMInit; - unsigned char b_TimingUnit; - unsigned char b_InterruptEnable; - double d_LowTiming; - double d_HighTiming; - unsigned int ul_RealLowTiming; - unsigned int ul_RealHighTiming; - } s_PWMInfo[2]; - unsigned char b_ClockSelection; - } s_PWMModuleInfo; - - /* ETM infos */ - struct { - struct { - unsigned char b_ETMEnable; - unsigned char b_ETMInterrupt; - } s_ETMInfo[2]; - unsigned char b_ETMInit; - unsigned char b_TimingUnit; - unsigned char b_ClockSelection; - double d_TimingInterval; - unsigned int ul_Timing; - } s_ETMModuleInfo; - - /* CDA infos */ - struct { - unsigned char b_CDAEnable; - unsigned char b_CDAInterrupt; - unsigned char b_CDAInit; - unsigned char b_FctSelection; - unsigned char b_CDAReadFIFOOverflow; - } s_CDAModuleInfo; - + int (*timer_config)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*timer_write)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*timer_read)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); + int (*timer_bits)(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *); }; -/* Private structure for the addi_apci3120 driver */ struct addi_private { - int iobase; int i_IobaseAmcc; /* base+size for AMCC chip */ int i_IobaseAddon; /* addon base address */ int i_IobaseReserved; - void __iomem *dw_AiBase; - struct pcilst_struct *amcc; /* ptr too AMCC data */ - unsigned char allocated; /* we have blocked card */ - unsigned char b_ValidDriver; /* driver is ok */ - unsigned char b_AiContinuous; /* we do unlimited AI */ - unsigned char b_AiInitialisation; unsigned int ui_AiActualScan; /* how many scans we finished */ - unsigned int ui_AiBufferPtr; /* data buffer ptr in samples */ unsigned int ui_AiNbrofChannels; /* how many channels is measured */ - unsigned int ui_AiScanLength; /* Length of actual scanlist */ - unsigned int ui_AiActualScanPosition; /* position in actual scan */ - unsigned int *pui_AiChannelList; /* actual chanlist */ unsigned int ui_AiChannelList[32]; /* actual chanlist */ - unsigned char b_AiChannelConfiguration[32]; /* actual chanlist */ unsigned int ui_AiReadData[32]; - unsigned int dw_AiInitialised; - unsigned int ui_AiTimer0; /* Timer Constant for Timer0 */ - unsigned int ui_AiTimer1; /* Timer constant for Timer1 */ - unsigned int ui_AiFlags; - unsigned int ui_AiDataLength; - short *AiData; /* Pointer to sample data */ - unsigned int ui_AiNbrofScans; /* number of scans to do */ unsigned short us_UseDma; /* To use Dma or not */ unsigned char b_DmaDoubleBuffer; /* we can use double buffering */ unsigned int ui_DmaActualBuffer; /* which buffer is used now */ - /* UPDATE-0.7.57->0.7.68 */ - /* unsigned int ul_DmaBufferVirtual[2]; pointers to begin of DMA buffer */ - short *ul_DmaBufferVirtual[2]; /* pointers to begin of DMA buffer */ + unsigned short *ul_DmaBufferVirtual[2]; /* pointers to DMA buffer */ unsigned int 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_DmaBufferSamples[2]; /* size in samples */ unsigned int ui_DmaBufferPages[2]; /* number of pages in buffer */ unsigned char b_DigitalOutputRegister; /* Digital Output Register */ unsigned char b_OutputMemoryStatus; - unsigned char b_AnalogInputChannelNbr; /* Analog input channel Nbr */ - unsigned char b_AnalogOutputChannelNbr; /* Analog input Output Nbr */ unsigned char b_TimerSelectMode; /* Contain data written at iobase + 0C */ unsigned char b_ModeSelectRegister; /* Contain data written at iobase + 0E */ unsigned short us_OutputRegister; /* Contain data written at iobase + 0 */ - unsigned char b_InterruptState; - unsigned char b_TimerInit; /* Specify if InitTimerWatchdog was load */ - unsigned char b_TimerStarted; /* Specify if timer 2 is running or not */ unsigned char b_Timer2Mode; /* Specify the timer 2 mode */ unsigned char b_Timer2Interrupt; /* Timer2 interrupt enable or disable */ - unsigned char b_AiCyclicAcquisition; /* indicate cyclic acquisition */ + unsigned int ai_running:1; unsigned char b_InterruptMode; /* eoc eos or dma */ unsigned char b_EocEosInterrupt; /* Enable disable eoc eos interrupt */ unsigned int ui_EocEosConversionTime; - unsigned char b_EocEosConversionTimeBase; unsigned char b_SingelDiff; unsigned char b_ExttrigEnable; /* To enable or disable external trigger */ /* Pointer to the current process */ struct task_struct *tsk_Current; - /* Hardware board infos for 1710 */ - struct { - unsigned int ui_Address; /* Board address */ - unsigned int ui_FlashAddress; - unsigned char b_InterruptNbr; /* Board interrupt number */ - unsigned char b_SlotNumber; /* PCI slot number */ - unsigned char b_BoardVersion; - unsigned int dw_MolduleConfiguration[4]; /* Module config */ - } s_BoardInfos; - - /* Interrupt infos */ - struct { - unsigned int ul_InterruptOccur; /* 0 : No interrupt occur */ - /* > 0 : Interrupt occur */ - unsigned int ui_Read; /* Read FIFO */ - unsigned int ui_Write; /* Write FIFO */ - struct { - unsigned char b_OldModuleMask; - unsigned int ul_OldInterruptMask; /* Interrupt mask */ - unsigned int ul_OldCounterLatchValue; /* Interrupt counter value */ - } s_FIFOInterruptParameters[APCI1710_SAVE_INTERRUPT]; - } s_InterruptParameters; - - union str_ModuleInfo s_ModuleInfo[4]; - unsigned int ul_TTLPortConfiguration[10]; - /* Parameters read from EEPROM overriding static board info */ struct { int i_NbrAiChannel; /* num of A/D chans */ @@ -442,7 +156,6 @@ struct addi_private { int i_NbrDiChannel; /* Number of DI channels */ int i_NbrDoChannel; /* Number of DO channels */ int i_DoMaxdata; /* data to set all channels high */ - int i_Dma; /* dma present or not */ int i_Timer; /* timer subdevice present or not */ unsigned int ui_MinAcquisitiontimeNs; /* Minimum Acquisition in Nano secs */ @@ -450,14 +163,3 @@ struct addi_private { /* Minimum Delay in Nano secs */ } s_EeParameters; }; - -static unsigned short pci_list_builded; /* set to 1 when list of card is known */ - -/* Function declarations */ -static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int i_ADDI_Detach(struct comedi_device *dev); -static int i_ADDI_Reset(struct comedi_device *dev); - -static irqreturn_t v_ADDI_Interrupt(int irq, void *d); -static int i_ADDIDATA_InsnReadEeprom(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c index 3a9339b9261..aafc172f3a9 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_eeprom.c @@ -1,1162 +1,360 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : ADDI DATA | Compiler : GCC | - | Modulname : addi_eeprom.c | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-----------------------------------------------------------------------+ - | Description : ADDI EEPROM Module | - +-----------------------------------------------------------------------+ - | UPDATE'S | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ -#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ -#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ -#define EE76_CMD_LEN 13 /* bits in instructions */ -#define EE_READ 0x0180 /* 01 1000 0000 read instruction */ - -#define EEPROM_DIGITALINPUT 0 -#define EEPROM_DIGITALOUTPUT 1 -#define EEPROM_ANALOGINPUT 2 -#define EEPROM_ANALOGOUTPUT 3 -#define EEPROM_TIMER 4 -#define EEPROM_WATCHDOG 5 + * addi_eeprom.c - ADDI EEPROM Module + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: Eric Stolz + * + * 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/delay.h> + +#define NVRAM_USER_DATA_START 0x100 + +#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ +#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ +#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ + +#define EE93C76_CLK_BIT (1 << 0) +#define EE93C76_CS_BIT (1 << 1) +#define EE93C76_DOUT_BIT (1 << 2) +#define EE93C76_DIN_BIT (1 << 3) +#define EE93C76_READ_CMD (0x0180 << 4) +#define EE93C76_CMD_LEN 13 + +#define EEPROM_DIGITALINPUT 0 +#define EEPROM_DIGITALOUTPUT 1 +#define EEPROM_ANALOGINPUT 2 +#define EEPROM_ANALOGOUTPUT 3 +#define EEPROM_TIMER 4 +#define EEPROM_WATCHDOG 5 #define EEPROM_TIMER_WATCHDOG_COUNTER 10 -struct str_Functionality { - unsigned char b_Type; - unsigned short w_Address; -}; - -struct str_MainHeader { - unsigned short w_HeaderSize; - unsigned char b_Nfunctions; - struct str_Functionality s_Functions[7]; -}; - -struct str_DigitalInputHeader { - unsigned short w_Nchannel; - unsigned char b_Interruptible; - unsigned short w_NinterruptLogic; -}; - -struct str_DigitalOutputHeader { - - unsigned short w_Nchannel; -}; - - -/* used for timer as well as watchdog */ - -struct str_TimerDetails { - - unsigned short w_HeaderSize; - unsigned char b_Resolution; - unsigned char b_Mode; /* in case of Watchdog it is functionality */ - unsigned short w_MinTiming; - unsigned char b_TimeBase; -}; - -struct str_TimerMainHeader { - - - unsigned short w_Ntimer; - struct str_TimerDetails s_TimerDetails[4]; /* supports 4 timers */ -}; - - -struct str_AnalogOutputHeader { - unsigned short w_Nchannel; - unsigned char b_Resolution; -}; - -struct str_AnalogInputHeader { - unsigned short w_Nchannel; - unsigned short w_MinConvertTiming; - unsigned short w_MinDelayTiming; - unsigned char b_HasDma; - unsigned char b_Resolution; -}; - - - /*****************************************/ - /* Read Header Functions */ - /*****************************************/ - -int i_EepromReadMainHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, struct comedi_device *dev); - -int i_EepromReadDigitalInputHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_DigitalInputHeader *s_Header); - -int i_EepromReadDigitalOutputHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_DigitalOutputHeader *s_Header); - -int i_EepromReadTimerHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_TimerMainHeader *s_Header); - -int i_EepromReadAnlogOutputHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_AnalogOutputHeader *s_Header); - -int i_EepromReadAnlogInputHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_AnalogInputHeader *s_Header); - - /******************************************/ - /* Eeprom Specific Functions */ - /******************************************/ -unsigned short w_EepromReadWord(unsigned short w_PCIBoardEepromAddress, char *pc_PCIChipInformation, - unsigned short w_EepromStartAddress); -void v_EepromWaitBusy(unsigned short w_PCIBoardEepromAddress); -void v_EepromClock76(unsigned int dw_Address, unsigned int dw_RegisterValue); -void v_EepromWaitBusy(unsigned short w_PCIBoardEepromAddress); -void v_EepromSendCommand76(unsigned int dw_Address, unsigned int dw_EepromCommand, - unsigned char b_DataLengthInBits); -void v_EepromCs76Read(unsigned int dw_Address, unsigned short w_offset, unsigned short *pw_Value); - -/* -+----------------------------------------------------------------------------+ -| Function Name : unsigned short w_EepromReadWord | -| (unsigned short w_PCIBoardEepromAddress, | -| char * pc_PCIChipInformation, | -| unsigned short w_EepromStartAddress) | -+----------------------------------------------------------------------------+ -| Task : Read from eepromn a word | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | -| | -| char *pc_PCIChipInformation : PCI Chip Type. | -| | -| unsigned short w_EepromStartAddress : Selected eeprom address | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : Read word value from eeprom | -+----------------------------------------------------------------------------+ -*/ - -unsigned short w_EepromReadWord(unsigned short w_PCIBoardEepromAddress, char *pc_PCIChipInformation, - unsigned short w_EepromStartAddress) +static void addi_eeprom_clk_93c76(unsigned long iobase, unsigned int val) { - - unsigned char b_Counter = 0; - - unsigned char b_ReadByte = 0; - - unsigned char b_ReadLowByte = 0; - - unsigned char b_ReadHighByte = 0; - - unsigned char b_SelectedAddressLow = 0; - - unsigned char b_SelectedAddressHigh = 0; - - unsigned short w_ReadWord = 0; - - /**************************/ - - /* Test the PCI chip type */ - - /**************************/ - - if ((!strcmp(pc_PCIChipInformation, "S5920")) || - (!strcmp(pc_PCIChipInformation, "S5933"))) - { - - for (b_Counter = 0; b_Counter < 2; b_Counter++) - { - - b_SelectedAddressLow = (w_EepromStartAddress + b_Counter) % 256; /* Read the low 8 bit part */ - - b_SelectedAddressHigh = (w_EepromStartAddress + b_Counter) / 256; /* Read the high 8 bit part */ - - /************************************/ - - /* Select the load low address mode */ - - /************************************/ - - outb(NVCMD_LOAD_LOW, w_PCIBoardEepromAddress + 0x3F); - - /****************/ - - /* Wait on busy */ - - /****************/ - - v_EepromWaitBusy(w_PCIBoardEepromAddress); - - /************************/ - - /* Load the low address */ - - /************************/ - - outb(b_SelectedAddressLow, - w_PCIBoardEepromAddress + 0x3E); - - /****************/ - - /* Wait on busy */ - - /****************/ - - v_EepromWaitBusy(w_PCIBoardEepromAddress); - - /*************************************/ - - /* Select the load high address mode */ - - /*************************************/ - - outb(NVCMD_LOAD_HIGH, w_PCIBoardEepromAddress + 0x3F); - - /****************/ - - /* Wait on busy */ - - /****************/ - - v_EepromWaitBusy(w_PCIBoardEepromAddress); - - /*************************/ - - /* Load the high address */ - - /*************************/ - - outb(b_SelectedAddressHigh, - w_PCIBoardEepromAddress + 0x3E); - - /****************/ - - /* Wait on busy */ - - /****************/ - - v_EepromWaitBusy(w_PCIBoardEepromAddress); - - /************************/ - - /* Select the READ mode */ - - /************************/ - - outb(NVCMD_BEGIN_READ, w_PCIBoardEepromAddress + 0x3F); - - /****************/ - - /* Wait on busy */ - - /****************/ - - v_EepromWaitBusy(w_PCIBoardEepromAddress); - - /*****************************/ - - /* Read data into the EEPROM */ - - /*****************************/ - - b_ReadByte = inb(w_PCIBoardEepromAddress + 0x3E); - - /****************/ - - /* Wait on busy */ - - /****************/ - - v_EepromWaitBusy(w_PCIBoardEepromAddress); - - /*********************************/ - - /* Select the upper address part */ - - /*********************************/ - - if (b_Counter == 0) - { - - b_ReadLowByte = b_ReadByte; - - } /* if(b_Counter==0) */ - - else - { - - b_ReadHighByte = b_ReadByte; - - } /* if(b_Counter==0) */ - - } /* for (b_Counter=0; b_Counter<2; b_Counter++) */ - - w_ReadWord = (b_ReadLowByte | (((unsigned short) b_ReadHighByte) * 256)); - - } /* end of if ((!strcmp(pc_PCIChipInformation, "S5920")) || (!strcmp(pc_PCIChipInformation, "S5933"))) */ - - if (!strcmp(pc_PCIChipInformation, "93C76")) - { - - /*************************************/ - - /* Read 16 bit from the EEPROM 93C76 */ - - /*************************************/ - - v_EepromCs76Read(w_PCIBoardEepromAddress, w_EepromStartAddress, - &w_ReadWord); - - } - - return w_ReadWord; - -} - -/* - -+----------------------------------------------------------------------------+ - -| Function Name : void v_EepromWaitBusy | - -| (unsigned short w_PCIBoardEepromAddress) | - -+----------------------------------------------------------------------------+ - -| Task : Wait the busy flag from PCI controller | - -+----------------------------------------------------------------------------+ - -| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom base address | - -+----------------------------------------------------------------------------+ - -| Output Parameters : - | - -+----------------------------------------------------------------------------+ - -| Return Value : - | - -+----------------------------------------------------------------------------+ - -*/ - -void v_EepromWaitBusy(unsigned short w_PCIBoardEepromAddress) -{ - - unsigned char b_EepromBusy = 0; - - do - { - - /*************/ - - /* IMPORTANT */ - - /*************/ - - /************************************************************************/ - - /* An error has been written in the AMCC 5933 book at the page B-13 */ - - /* Ex: if you read a byte and look for the busy statusEEPROM=0x80 and */ - - /* the operator register is AMCC_OP_REG_MCSR+3 */ - - /* unsigned short read EEPROM=0x8000 andAMCC_OP_REG_MCSR+2 */ - - /* unsigned int read EEPROM=0x80000000 and AMCC_OP_REG_MCSR */ - - /************************************************************************/ - - b_EepromBusy = inb(w_PCIBoardEepromAddress + 0x3F); - b_EepromBusy = b_EepromBusy & 0x80; - - } while (b_EepromBusy == 0x80); - -} - -/* - -+---------------------------------------------------------------------------------+ - -| Function Name : void v_EepromClock76(unsigned int dw_Address, | - -| unsigned int dw_RegisterValue) | - -+---------------------------------------------------------------------------------+ - -| Task : This function sends the clocking sequence to the EEPROM. | - -+---------------------------------------------------------------------------------+ - -| Input Parameters : unsigned int dw_Address : PCI eeprom base address | - -| unsigned int dw_RegisterValue : PCI eeprom register value to write.| - -+---------------------------------------------------------------------------------+ - -| Output Parameters : - | - -+---------------------------------------------------------------------------------+ - -| Return Value : - | - -+---------------------------------------------------------------------------------+ - -*/ - -void v_EepromClock76(unsigned int dw_Address, unsigned int dw_RegisterValue) -{ - - /************************/ - - /* Set EEPROM clock Low */ - - /************************/ - - outl(dw_RegisterValue & 0x6, dw_Address); - - /***************/ - - /* Wait 0.1 ms */ - - /***************/ - + outl(val & ~EE93C76_CLK_BIT, iobase); udelay(100); - /*************************/ - - /* Set EEPROM clock High */ - - /*************************/ - - outl(dw_RegisterValue | 0x1, dw_Address); - - /***************/ - - /* Wait 0.1 ms */ - - /***************/ - + outl(val | EE93C76_CLK_BIT, iobase); udelay(100); - } -/* - -+---------------------------------------------------------------------------------+ - -| Function Name : void v_EepromSendCommand76(unsigned int dw_Address, | - -| unsigned int dw_EepromCommand, | - -| unsigned char b_DataLengthInBits) | - -+---------------------------------------------------------------------------------+ - -| Task : This function sends a Command to the EEPROM 93C76. | - -+---------------------------------------------------------------------------------+ - -| Input Parameters : unsigned int dw_Address : PCI eeprom base address | - -| unsigned int dw_EepromCommand : PCI eeprom command to write. | - -| unsigned char b_DataLengthInBits : PCI eeprom command data length. | - -+---------------------------------------------------------------------------------+ - -| Output Parameters : - | - -+---------------------------------------------------------------------------------+ - -| Return Value : - | - -+---------------------------------------------------------------------------------+ - -*/ - -void v_EepromSendCommand76(unsigned int dw_Address, unsigned int dw_EepromCommand, - unsigned char b_DataLengthInBits) +static unsigned int addi_eeprom_cmd_93c76(unsigned long iobase, + unsigned int cmd, + unsigned char len) { - - char c_BitPos = 0; - - unsigned int dw_RegisterValue = 0; - - /*****************************/ - - /* Enable EEPROM Chip Select */ - - /*****************************/ - - dw_RegisterValue = 0x2; - - /********************************************************************/ + unsigned int val = EE93C76_CS_BIT; + int i; /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */ - - /********************************************************************/ - - outl(dw_RegisterValue, dw_Address); - - /***************/ - - /* Wait 0.1 ms */ - - /***************/ - + outl(val, iobase); udelay(100); - /*******************************************/ - /* Send EEPROM command - one bit at a time */ - - /*******************************************/ - - for (c_BitPos = (b_DataLengthInBits - 1); c_BitPos >= 0; c_BitPos--) - { - - /**********************************/ - - /* Check if current bit is 0 or 1 */ - - /**********************************/ - - if (dw_EepromCommand & (1 << c_BitPos)) - { - - /***********/ - - /* Write 1 */ - - /***********/ - - dw_RegisterValue = dw_RegisterValue | 0x4; - - } - + for (i = (len - 1); i >= 0; i--) { + if (cmd & (1 << i)) + val |= EE93C76_DOUT_BIT; else - { - - /***********/ - - /* Write 0 */ - - /***********/ - - dw_RegisterValue = dw_RegisterValue & 0x3; - - } - - /*********************/ + val &= ~EE93C76_DOUT_BIT; /* Write the command */ - - /*********************/ - - outl(dw_RegisterValue, dw_Address); - - /***************/ - - /* Wait 0.1 ms */ - - /***************/ - + outl(val, iobase); udelay(100); - /****************************/ - - /* Trigger the EEPROM clock */ - - /****************************/ - - v_EepromClock76(dw_Address, dw_RegisterValue); - + addi_eeprom_clk_93c76(iobase, val); } - + return val; } -/* - -+---------------------------------------------------------------------------------+ - -| Function Name : void v_EepromCs76Read(unsigned int dw_Address, | - -| unsigned short w_offset, | - -| unsigned short * pw_Value) | - -+---------------------------------------------------------------------------------+ - -| Task : This function read a value from the EEPROM 93C76. | - -+---------------------------------------------------------------------------------+ - -| Input Parameters : unsigned int dw_Address : PCI eeprom base address | - -| unsigned short w_offset : Offset of the address to read | - -| unsigned short * pw_Value : PCI eeprom 16 bit read value. | - -+---------------------------------------------------------------------------------+ - -| Output Parameters : - | - -+---------------------------------------------------------------------------------+ - -| Return Value : - | - -+---------------------------------------------------------------------------------+ - -*/ - -void v_EepromCs76Read(unsigned int dw_Address, unsigned short w_offset, unsigned short *pw_Value) +static unsigned short addi_eeprom_readw_93c76(unsigned long iobase, + unsigned short addr) { - - char c_BitPos = 0; - - unsigned int dw_RegisterValue = 0; - - unsigned int dw_RegisterValueRead = 0; - - /*************************************************/ + unsigned short val = 0; + unsigned int cmd; + unsigned int tmp; + int i; /* Send EEPROM read command and offset to EEPROM */ - - /*************************************************/ - - v_EepromSendCommand76(dw_Address, (EE_READ << 4) | (w_offset / 2), - EE76_CMD_LEN); - - /*******************************/ - - /* Get the last register value */ - - /*******************************/ - - dw_RegisterValue = (((w_offset / 2) & 0x1) << 2) | 0x2; - - /*****************************/ - - /* Set the 16-bit value of 0 */ - - /*****************************/ - - *pw_Value = 0; - - /************************/ + cmd = EE93C76_READ_CMD | (addr / 2); + cmd = addi_eeprom_cmd_93c76(iobase, cmd, EE93C76_CMD_LEN); /* Get the 16-bit value */ + for (i = 0; i < 16; i++) { + addi_eeprom_clk_93c76(iobase, cmd); - /************************/ - - for (c_BitPos = 0; c_BitPos < 16; c_BitPos++) - { - - /****************************/ - - /* Trigger the EEPROM clock */ - - /****************************/ - - v_EepromClock76(dw_Address, dw_RegisterValue); - - /**********************/ - - /* Get the result bit */ - - /**********************/ - - dw_RegisterValueRead = inl(dw_Address); - - /***************/ - - /* Wait 0.1 ms */ - - /***************/ - + tmp = inl(iobase); udelay(100); - /***************************************/ - - /* Get bit value and shift into result */ - - /***************************************/ - - if (dw_RegisterValueRead & 0x8) - { - - /**********/ + val <<= 1; + if (tmp & EE93C76_DIN_BIT) + val |= 0x1; + } - /* Read 1 */ + /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */ + outl(0, iobase); + udelay(100); - /**********/ + return val; +} - *pw_Value = (*pw_Value << 1) | 0x1; +static void addi_eeprom_nvram_wait(unsigned long iobase) +{ + unsigned char val; - } + do { + val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD); + } while (val & 0x80); +} +static unsigned short addi_eeprom_readw_nvram(unsigned long iobase, + unsigned short addr) +{ + unsigned short val = 0; + unsigned char tmp; + unsigned char i; + + for (i = 0; i < 2; i++) { + /* Load the low 8 bit address */ + outb(NVCMD_LOAD_LOW, iobase + AMCC_OP_REG_MCSR_NVCMD); + addi_eeprom_nvram_wait(iobase); + outb((addr + i) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); + addi_eeprom_nvram_wait(iobase); + + /* Load the high 8 bit address */ + outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD); + addi_eeprom_nvram_wait(iobase); + outb(((addr + i) >> 8) & 0xff, + iobase + AMCC_OP_REG_MCSR_NVDATA); + addi_eeprom_nvram_wait(iobase); + + /* Read the eeprom data byte */ + outb(NVCMD_BEGIN_READ, iobase + AMCC_OP_REG_MCSR_NVCMD); + addi_eeprom_nvram_wait(iobase); + tmp = inb(iobase + AMCC_OP_REG_MCSR_NVDATA); + addi_eeprom_nvram_wait(iobase); + + if (i == 0) + val |= tmp; else - { - - /**********/ - - /* Read 0 */ + val |= (tmp << 8); + } - /**********/ + return val; +} - *pw_Value = (*pw_Value << 1); +static unsigned short addi_eeprom_readw(unsigned long iobase, + char *type, + unsigned short addr) +{ + unsigned short val = 0; - } + /* Add the offset to the start of the user data */ + addr += NVRAM_USER_DATA_START; - } + if (!strcmp(type, "S5920") || !strcmp(type, "S5933")) + val = addi_eeprom_readw_nvram(iobase, addr); - /*************************/ + if (!strcmp(type, "93C76")) + val = addi_eeprom_readw_93c76(iobase, addr); - /* Clear all EEPROM bits */ + return val; +} - /*************************/ +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); + struct addi_private *devpriv = dev->private; + char *type = this_board->pc_EepromChip; + unsigned short tmp; - dw_RegisterValue = 0x0; + /* Number of channels */ + tmp = addi_eeprom_readw(iobase, type, addr + 6); + devpriv->s_EeParameters.i_NbrDiChannel = tmp; - /********************************************************************/ + /* Interruptible or not */ + tmp = addi_eeprom_readw(iobase, type, addr + 8); + tmp = (tmp >> 7) & 0x01; - /* Toggle EEPROM's Chip select to get it out of Shift Register Mode */ + /* How many interruptible logic */ + tmp = addi_eeprom_readw(iobase, type, addr + 10); +} - /********************************************************************/ +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); + struct addi_private *devpriv = dev->private; + char *type = this_board->pc_EepromChip; + unsigned short tmp; - outl(dw_RegisterValue, dw_Address); + /* Number of channels */ + tmp = addi_eeprom_readw(iobase, type, addr + 6); + devpriv->s_EeParameters.i_NbrDoChannel = tmp; - /***************/ + devpriv->s_EeParameters.i_DoMaxdata = 0xffffffff >> (32 - tmp); +} - /* Wait 0.1 ms */ +static void addi_eeprom_read_timer_info(struct comedi_device *dev, + unsigned long iobase, + unsigned short addr) +{ + struct addi_private *devpriv = dev->private; +#if 0 + const struct addi_board *this_board = comedi_board(dev); + char *type = this_board->pc_EepromChip; + unsigned short offset = 0; + unsigned short ntimers; + unsigned short tmp; + int i; + + /* Number of Timers */ + ntimers = addi_eeprom_readw(iobase, type, addr + 6); + + /* Read header size */ + for (i = 0; i < ntimers; i++) { + unsigned short size; + unsigned short res; + unsigned short mode; + unsigned short min_timing; + unsigned short timebase; + + size = addi_eeprom_readw(iobase, type, addr + 8 + offset + 0); + + /* Resolution / Mode */ + tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 2); + res = (tmp >> 10) & 0x3f; + mode = (tmp >> 4) & 0x3f; + + /* MinTiming / Timebase */ + tmp = addi_eeprom_readw(iobase, type, addr + 8 + offset + 4); + min_timing = (tmp >> 6) & 0x3ff; + Timebase = tmp & 0x3f; + + offset += size; + } +#endif + /* Timer subdevice present */ + devpriv->s_EeParameters.i_Timer = 1; +} - /***************/ +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); + struct addi_private *devpriv = dev->private; + char *type = this_board->pc_EepromChip; + unsigned short tmp; + + /* No of channels for 1st hard component */ + tmp = addi_eeprom_readw(iobase, type, addr + 10); + devpriv->s_EeParameters.i_NbrAoChannel = (tmp >> 4) & 0x3ff; + + /* Resolution for 1st hard component */ + tmp = addi_eeprom_readw(iobase, type, addr + 16); + tmp = (tmp >> 8) & 0xff; + devpriv->s_EeParameters.i_AoMaxdata = 0xfff >> (16 - tmp); +} - udelay(100); +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); + struct addi_private *devpriv = dev->private; + char *type = this_board->pc_EepromChip; + unsigned short offset; + unsigned short tmp; + + /* No of channels for 1st hard component */ + tmp = addi_eeprom_readw(iobase, type, addr + 10); + devpriv->s_EeParameters.i_NbrAiChannel = (tmp >> 4) & 0x3ff; + if (!strcmp(this_board->pc_DriverName, "apci3200")) + devpriv->s_EeParameters.i_NbrAiChannel *= 4; + + tmp = addi_eeprom_readw(iobase, type, addr + 16); + devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = tmp * 1000; + + tmp = addi_eeprom_readw(iobase, type, addr + 30); + devpriv->s_EeParameters.ui_MinDelaytimeNs = tmp * 1000; + + tmp = addi_eeprom_readw(iobase, type, addr + 20); + /* dma = (tmp >> 13) & 0x01; */ + + tmp = addi_eeprom_readw(iobase, type, addr + 72) & 0xff; + if (tmp) { /* > 0 */ + /* offset of first analog input single header */ + offset = 74 + (2 * tmp) + (10 * (1 + (tmp / 16))); + } else { /* = 0 */ + offset = 74; + } + /* Resolution */ + tmp = addi_eeprom_readw(iobase, type, addr + offset + 2) & 0x1f; + devpriv->s_EeParameters.i_AiMaxdata = 0xffff >> (16 - tmp); } - /******************************************/ - /* EEPROM HEADER READ FUNCTIONS */ - /******************************************/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_EepromReadMainHeader(unsigned short w_PCIBoardEepromAddress, | -| char * pc_PCIChipInformation,struct comedi_device *dev) | -+----------------------------------------------------------------------------+ -| Task : Read from eeprom Main Header | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | -| | -| char *pc_PCIChipInformation : PCI Chip Type. | -| | -| struct comedi_device *dev : comedi device structure | -| pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -+----------------------------------------------------------------------------+ -*/ - -int i_EepromReadMainHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, struct comedi_device *dev) +static void addi_eeprom_read_info(struct comedi_device *dev, + unsigned long iobase) { - unsigned short w_Temp, i, w_Count = 0; - unsigned int ui_Temp; - struct str_MainHeader s_MainHeader; - struct str_DigitalInputHeader s_DigitalInputHeader; - struct str_DigitalOutputHeader s_DigitalOutputHeader; - /* struct str_TimerMainHeader s_TimerMainHeader,s_WatchdogMainHeader; */ - struct str_AnalogOutputHeader s_AnalogOutputHeader; - struct str_AnalogInputHeader s_AnalogInputHeader; - - /* Read size */ - s_MainHeader.w_HeaderSize = - w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, - 0x100 + 8); - - /* Read nbr of functionality */ - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + 10); - s_MainHeader.b_Nfunctions = (unsigned char) w_Temp & 0x00FF; + const struct addi_board *this_board = comedi_board(dev); + char *type = this_board->pc_EepromChip; + unsigned short size; + unsigned char nfuncs; + int i; + + size = addi_eeprom_readw(iobase, type, 8); + nfuncs = addi_eeprom_readw(iobase, type, 10) & 0xff; /* Read functionality details */ - for (i = 0; i < s_MainHeader.b_Nfunctions; i++) { - /* Read Type */ - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + 12 + w_Count); - s_MainHeader.s_Functions[i].b_Type = (unsigned char) w_Temp & 0x3F; - w_Count = w_Count + 2; - /* Read Address */ - s_MainHeader.s_Functions[i].w_Address = - w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + 12 + w_Count); - w_Count = w_Count + 2; - } + for (i = 0; i < nfuncs; i++) { + unsigned short offset = i * 4; + unsigned short addr; + unsigned char func; - /* Display main header info */ - for (i = 0; i < s_MainHeader.b_Nfunctions; i++) { + func = addi_eeprom_readw(iobase, type, 12 + offset) & 0x3f; + addr = addi_eeprom_readw(iobase, type, 14 + offset); - switch (s_MainHeader.s_Functions[i].b_Type) { + switch (func) { case EEPROM_DIGITALINPUT: - i_EepromReadDigitalInputHeader(w_PCIBoardEepromAddress, - pc_PCIChipInformation, - s_MainHeader.s_Functions[i].w_Address, - &s_DigitalInputHeader); - devpriv->s_EeParameters.i_NbrDiChannel = - s_DigitalInputHeader.w_Nchannel; + addi_eeprom_read_di_info(dev, iobase, addr); break; case EEPROM_DIGITALOUTPUT: - i_EepromReadDigitalOutputHeader(w_PCIBoardEepromAddress, - pc_PCIChipInformation, - s_MainHeader.s_Functions[i].w_Address, - &s_DigitalOutputHeader); - devpriv->s_EeParameters.i_NbrDoChannel = - s_DigitalOutputHeader.w_Nchannel; - ui_Temp = 0xffffffff; - devpriv->s_EeParameters.i_DoMaxdata = - ui_Temp >> (32 - - devpriv->s_EeParameters.i_NbrDoChannel); + addi_eeprom_read_do_info(dev, iobase, addr); break; case EEPROM_ANALOGINPUT: - i_EepromReadAnlogInputHeader(w_PCIBoardEepromAddress, - pc_PCIChipInformation, - s_MainHeader.s_Functions[i].w_Address, - &s_AnalogInputHeader); - if (!(strcmp(this_board->pc_DriverName, "apci3200"))) - devpriv->s_EeParameters.i_NbrAiChannel = - s_AnalogInputHeader.w_Nchannel * 4; - else - devpriv->s_EeParameters.i_NbrAiChannel = - s_AnalogInputHeader.w_Nchannel; - devpriv->s_EeParameters.i_Dma = - s_AnalogInputHeader.b_HasDma; - devpriv->s_EeParameters.ui_MinAcquisitiontimeNs = - (unsigned int) s_AnalogInputHeader.w_MinConvertTiming * - 1000; - devpriv->s_EeParameters.ui_MinDelaytimeNs = - (unsigned int) s_AnalogInputHeader.w_MinDelayTiming * - 1000; - ui_Temp = 0xffff; - devpriv->s_EeParameters.i_AiMaxdata = - ui_Temp >> (16 - - s_AnalogInputHeader.b_Resolution); + addi_eeprom_read_ai_info(dev, iobase, addr); break; case EEPROM_ANALOGOUTPUT: - i_EepromReadAnlogOutputHeader(w_PCIBoardEepromAddress, - pc_PCIChipInformation, - s_MainHeader.s_Functions[i].w_Address, - &s_AnalogOutputHeader); - devpriv->s_EeParameters.i_NbrAoChannel = - s_AnalogOutputHeader.w_Nchannel; - ui_Temp = 0xffff; - devpriv->s_EeParameters.i_AoMaxdata = - ui_Temp >> (16 - - s_AnalogOutputHeader.b_Resolution); + addi_eeprom_read_ao_info(dev, iobase, addr); break; case EEPROM_TIMER: - /* Timer subdevice present */ - devpriv->s_EeParameters.i_Timer = 1; - break; - case EEPROM_WATCHDOG: - /* Timer subdevice present */ - devpriv->s_EeParameters.i_Timer = 1; - break; - case EEPROM_TIMER_WATCHDOG_COUNTER: - /* Timer subdevice present */ - devpriv->s_EeParameters.i_Timer = 1; + addi_eeprom_read_timer_info(dev, iobase, addr); break; } } - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_EepromReadDigitalInputHeader(unsigned short | -| w_PCIBoardEepromAddress,char *pc_PCIChipInformation, | -| unsigned short w_Address,struct str_DigitalInputHeader *s_Header) | -| | -+----------------------------------------------------------------------------+ -| Task : Read Digital Input Header | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | -| | -| char *pc_PCIChipInformation : PCI Chip Type. | -| | -| struct str_DigitalInputHeader *s_Header: Digita Input Header | -| Pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -+----------------------------------------------------------------------------+ -*/ -int i_EepromReadDigitalInputHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_DigitalInputHeader *s_Header) -{ - unsigned short w_Temp; - - /* read nbr of channels */ - s_Header->w_Nchannel = - w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, - 0x100 + w_Address + 6); - - /* interruptible or not */ - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + w_Address + 8); - s_Header->b_Interruptible = (unsigned char) (w_Temp >> 7) & 0x01; - -/* How many interruptible logic */ - s_Header->w_NinterruptLogic = - w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, - 0x100 + w_Address + 10); - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_EepromReadDigitalOutputHeader(unsigned short | -| w_PCIBoardEepromAddress,char *pc_PCIChipInformation, | -| unsigned short w_Address,struct str_DigitalOutputHeader *s_Header) | -| | -+----------------------------------------------------------------------------+ -| Task : Read Digital Output Header | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | -| | -| char *pc_PCIChipInformation : PCI Chip Type. | -| | -| struct str_DigitalOutputHeader *s_Header: Digital Output Header| -| Pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -+----------------------------------------------------------------------------+ -*/ -int i_EepromReadDigitalOutputHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_DigitalOutputHeader *s_Header) -{ -/* Read Nbr channels */ - s_Header->w_Nchannel = - w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, - 0x100 + w_Address + 6); - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_EepromReadTimerHeader(unsigned short w_PCIBoardEepromAddress, | -| char *pc_PCIChipInformation,WORD w_Address, | -| struct str_TimerMainHeader *s_Header) | -+----------------------------------------------------------------------------+ -| Task : Read Timer or Watchdog Header | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | -| | -| char *pc_PCIChipInformation : PCI Chip Type. | -| | -| struct str_TimerMainHeader *s_Header: Timer Header | -| Pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -+----------------------------------------------------------------------------+ -*/ -int i_EepromReadTimerHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_TimerMainHeader *s_Header) -{ - - unsigned short i, w_Size = 0, w_Temp; - -/* Read No of Timer */ - s_Header->w_Ntimer = - w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, - 0x100 + w_Address + 6); -/* Read header size */ - - for (i = 0; i < s_Header->w_Ntimer; i++) { - s_Header->s_TimerDetails[i].w_HeaderSize = - w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, - 0x100 + w_Address + 8 + w_Size + 0); - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, - 0x100 + w_Address + 8 + w_Size + 2); - - /* Read Resolution */ - s_Header->s_TimerDetails[i].b_Resolution = - (unsigned char) (w_Temp >> 10) & 0x3F; - - /* Read Mode */ - s_Header->s_TimerDetails[i].b_Mode = - (unsigned char) (w_Temp >> 4) & 0x3F; - - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, - 0x100 + w_Address + 8 + w_Size + 4); - - /* Read MinTiming */ - s_Header->s_TimerDetails[i].w_MinTiming = (w_Temp >> 6) & 0x3FF; - - /* Read Timebase */ - s_Header->s_TimerDetails[i].b_TimeBase = (unsigned char) (w_Temp) & 0x3F; - w_Size += s_Header->s_TimerDetails[i].w_HeaderSize; - } - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_EepromReadAnlogOutputHeader(unsigned short | -| w_PCIBoardEepromAddress,char *pc_PCIChipInformation, | -| unsigned short w_Address,str_AnalogOutputHeader *s_Header) | -+----------------------------------------------------------------------------+ -| Task : Read Nalog Output Header | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | -| | -| char *pc_PCIChipInformation : PCI Chip Type. | -| | -| str_AnalogOutputHeader *s_Header:Anlog Output Header | -| Pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -+----------------------------------------------------------------------------+ -*/ - -int i_EepromReadAnlogOutputHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_AnalogOutputHeader *s_Header) -{ - unsigned short w_Temp; - /* No of channels for 1st hard component */ - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + w_Address + 10); - s_Header->w_Nchannel = (w_Temp >> 4) & 0x03FF; - /* Resolution for 1st hard component */ - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + w_Address + 16); - s_Header->b_Resolution = (unsigned char) (w_Temp >> 8) & 0xFF; - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_EepromReadAnlogInputHeader(unsigned short | -| w_PCIBoardEepromAddress,char *pc_PCIChipInformation, | -| unsigned short w_Address,struct str_AnalogInputHeader *s_Header) | -+----------------------------------------------------------------------------+ -| Task : Read Nalog Output Header | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned short w_PCIBoardEepromAddress : PCI eeprom address | -| | -| char *pc_PCIChipInformation : PCI Chip Type. | -| | -| struct str_AnalogInputHeader *s_Header:Anlog Input Header | -| Pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -+----------------------------------------------------------------------------+ -*/ - -/* Reads only for ONE hardware component */ -int i_EepromReadAnlogInputHeader(unsigned short w_PCIBoardEepromAddress, - char *pc_PCIChipInformation, unsigned short w_Address, - struct str_AnalogInputHeader *s_Header) -{ - unsigned short w_Temp, w_Offset; - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + w_Address + 10); - s_Header->w_Nchannel = (w_Temp >> 4) & 0x03FF; - s_Header->w_MinConvertTiming = - w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, - 0x100 + w_Address + 16); - s_Header->w_MinDelayTiming = - w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, - 0x100 + w_Address + 30); - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + w_Address + 20); - s_Header->b_HasDma = (w_Temp >> 13) & 0x01; /* whether dma present or not */ - - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, pc_PCIChipInformation, 0x100 + w_Address + 72); /* reading Y */ - w_Temp = w_Temp & 0x00FF; - if (w_Temp) /* Y>0 */ - { - w_Offset = 74 + (2 * w_Temp) + (10 * (1 + (w_Temp / 16))); /* offset of first analog input single header */ - w_Offset = w_Offset + 2; /* resolution */ - } else /* Y=0 */ - { - w_Offset = 74; - w_Offset = w_Offset + 2; /* resolution */ - } - -/* read Resolution */ - w_Temp = w_EepromReadWord(w_PCIBoardEepromAddress, - pc_PCIChipInformation, 0x100 + w_Address + w_Offset); - s_Header->b_Resolution = w_Temp & 0x001F; /* last 5 bits */ - - return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h b/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h deleted file mode 100644 index 349e93c23e9..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h +++ /dev/null @@ -1,457 +0,0 @@ -/* - Modified by umesh on 16th may 2001 - Modified by sarath on 22nd may 2001 -*/ - -/* - comedi/drivers/amcc_s5933_v_58.h - - Stuff for AMCC S5933 PCI Controller - - Author: Michal Dobes <majkl@tesnet.cz> - - Inspirated from general-purpose AMCC S5933 PCI Matchmaker driver - made by Andrea Cisternino <acister@pcape1.pi.infn.it> - and as result of espionage from MITE code made by David A. Schleef. - Thanks to AMCC for their on-line documentation and bus master DMA - example. -*/ - -#ifndef _AMCC_S5933_H_ -#define _AMCC_S5933_H_ - -#include <linux/pci.h> -#include "../../comedidev.h" - -#ifdef PCI_SUPPORT_VER1 -#error Sorry, no support for 2.1.55 and older! :-(((( -#endif - -/***********Added by sarath for compatibility with APCI3120 - -*************************/ - -#define FIFO_ADVANCE_ON_BYTE_2 0x20000000 /* written on base0 */ - -#define AMWEN_ENABLE 0x02 /* added for step 6 dma written on base2 */ -#define A2P_FIFO_WRITE_ENABLE 0x01 - -#define AGCSTS_TC_ENABLE 0x10000000 /* Added for transfer count enable bit */ - -/* ADDON RELATED ADDITIONS */ -/* Constant */ -#define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00 -#define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200 -#define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L -#define APCI3120_AMWEN_ENABLE 0x02 -#define APCI3120_A2P_FIFO_WRITE_ENABLE 0x01 -#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 0x20000000L -#define APCI3120_ENABLE_WRITE_TC_INT 0x00004000L -#define APCI3120_CLEAR_WRITE_TC_INT 0x00040000L -#define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0 -#define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0 -#define APCI3120_DISABLE_BUS_MASTER_PCI 0x0 - - /* ADD_ON ::: this needed since apci supports 16 bit interface to add on */ -#define APCI3120_ADD_ON_AGCSTS_LOW 0x3C -#define APCI3120_ADD_ON_AGCSTS_HIGH APCI3120_ADD_ON_AGCSTS_LOW + 2 -#define APCI3120_ADD_ON_MWAR_LOW 0x24 -#define APCI3120_ADD_ON_MWAR_HIGH APCI3120_ADD_ON_MWAR_LOW + 2 -#define APCI3120_ADD_ON_MWTC_LOW 0x058 -#define APCI3120_ADD_ON_MWTC_HIGH APCI3120_ADD_ON_MWTC_LOW + 2 - -/* AMCC */ -#define APCI3120_AMCC_OP_MCSR 0x3C -#define APCI3120_AMCC_OP_REG_INTCSR 0x38 - -/*******from here all upward definitions are added by sarath */ - -/****************************************************************************/ -/* AMCC Operation Register Offsets - PCI */ -/****************************************************************************/ - -#define AMCC_OP_REG_OMB1 0x00 -#define AMCC_OP_REG_OMB2 0x04 -#define AMCC_OP_REG_OMB3 0x08 -#define AMCC_OP_REG_OMB4 0x0c -#define AMCC_OP_REG_IMB1 0x10 -#define AMCC_OP_REG_IMB2 0x14 -#define AMCC_OP_REG_IMB3 0x18 -#define AMCC_OP_REG_IMB4 0x1c -#define AMCC_OP_REG_FIFO 0x20 -#define AMCC_OP_REG_MWAR 0x24 -#define AMCC_OP_REG_MWTC 0x28 -#define AMCC_OP_REG_MRAR 0x2c -#define AMCC_OP_REG_MRTC 0x30 -#define AMCC_OP_REG_MBEF 0x34 -#define AMCC_OP_REG_INTCSR 0x38 -#define AMCC_OP_REG_INTCSR_SRC (AMCC_OP_REG_INTCSR + 2) /* int source */ -#define AMCC_OP_REG_INTCSR_FEC (AMCC_OP_REG_INTCSR + 3) /* FIFO ctrl */ -#define AMCC_OP_REG_MCSR 0x3c -#define AMCC_OP_REG_MCSR_NVDATA (AMCC_OP_REG_MCSR + 2) /* Data in byte 2 */ -#define AMCC_OP_REG_MCSR_NVCMD (AMCC_OP_REG_MCSR + 3) /* Command in byte 3 */ - -#define AMCC_FIFO_DEPTH_DWORD 8 -#define AMCC_FIFO_DEPTH_BYTES (8 * sizeof (u32)) - -/****************************************************************************/ -/* AMCC Operation Registers Size - PCI */ -/****************************************************************************/ - -#define AMCC_OP_REG_SIZE 64 /* in bytes */ - -/****************************************************************************/ -/* AMCC Operation Register Offsets - Add-on */ -/****************************************************************************/ - -#define AMCC_OP_REG_AIMB1 0x00 -#define AMCC_OP_REG_AIMB2 0x04 -#define AMCC_OP_REG_AIMB3 0x08 -#define AMCC_OP_REG_AIMB4 0x0c -#define AMCC_OP_REG_AOMB1 0x10 -#define AMCC_OP_REG_AOMB2 0x14 -#define AMCC_OP_REG_AOMB3 0x18 -#define AMCC_OP_REG_AOMB4 0x1c -#define AMCC_OP_REG_AFIFO 0x20 -#define AMCC_OP_REG_AMWAR 0x24 -#define AMCC_OP_REG_APTA 0x28 -#define AMCC_OP_REG_APTD 0x2c -#define AMCC_OP_REG_AMRAR 0x30 -#define AMCC_OP_REG_AMBEF 0x34 -#define AMCC_OP_REG_AINT 0x38 -#define AMCC_OP_REG_AGCSTS 0x3c -#define AMCC_OP_REG_AMWTC 0x58 -#define AMCC_OP_REG_AMRTC 0x5c - -/****************************************************************************/ -/* AMCC - Add-on General Control/Status Register */ -/****************************************************************************/ - -#define AGCSTS_CONTROL_MASK 0xfffff000 -#define AGCSTS_NV_ACC_MASK 0xe0000000 -#define AGCSTS_RESET_MASK 0x0e000000 -#define AGCSTS_NV_DA_MASK 0x00ff0000 -#define AGCSTS_BIST_MASK 0x0000f000 -#define AGCSTS_STATUS_MASK 0x000000ff -#define AGCSTS_TCZERO_MASK 0x000000c0 -#define AGCSTS_FIFO_ST_MASK 0x0000003f - -#define AGCSTS_RESET_MBFLAGS 0x08000000 -#define AGCSTS_RESET_P2A_FIFO 0x04000000 -#define AGCSTS_RESET_A2P_FIFO 0x02000000 -#define AGCSTS_RESET_FIFOS (AGCSTS_RESET_A2P_FIFO | AGCSTS_RESET_P2A_FIFO) - -#define AGCSTS_A2P_TCOUNT 0x00000080 -#define AGCSTS_P2A_TCOUNT 0x00000040 - -#define AGCSTS_FS_P2A_EMPTY 0x00000020 -#define AGCSTS_FS_P2A_HALF 0x00000010 -#define AGCSTS_FS_P2A_FULL 0x00000008 - -#define AGCSTS_FS_A2P_EMPTY 0x00000004 -#define AGCSTS_FS_A2P_HALF 0x00000002 -#define AGCSTS_FS_A2P_FULL 0x00000001 - -/****************************************************************************/ -/* AMCC - Add-on Interrupt Control/Status Register */ -/****************************************************************************/ - -#define AINT_INT_MASK 0x00ff0000 -#define AINT_SEL_MASK 0x0000ffff -#define AINT_IS_ENSEL_MASK 0x00001f1f - -#define AINT_INT_ASSERTED 0x00800000 -#define AINT_BM_ERROR 0x00200000 -#define AINT_BIST_INT 0x00100000 - -#define AINT_RT_COMPLETE 0x00080000 -#define AINT_WT_COMPLETE 0x00040000 - -#define AINT_OUT_MB_INT 0x00020000 -#define AINT_IN_MB_INT 0x00010000 - -#define AINT_READ_COMPL 0x00008000 -#define AINT_WRITE_COMPL 0x00004000 - -#define AINT_OMB_ENABLE 0x00001000 -#define AINT_OMB_SELECT 0x00000c00 -#define AINT_OMB_BYTE 0x00000300 - -#define AINT_IMB_ENABLE 0x00000010 -#define AINT_IMB_SELECT 0x0000000c -#define AINT_IMB_BYTE 0x00000003 - -/* Enable Bus Mastering */ -#define EN_A2P_TRANSFERS 0x00000400 -/* FIFO Flag Reset */ -#define RESET_A2P_FLAGS 0x04000000L -/* FIFO Relative Priority */ -#define A2P_HI_PRIORITY 0x00000100L -/* Identify Interrupt Sources */ -#define ANY_S593X_INT 0x00800000L -#define READ_TC_INT 0x00080000L -#define WRITE_TC_INT 0x00040000L -#define IN_MB_INT 0x00020000L -#define MASTER_ABORT_INT 0x00100000L -#define TARGET_ABORT_INT 0x00200000L -#define BUS_MASTER_INT 0x00200000L - -/****************************************************************************/ - -struct pcilst_struct { - struct pcilst_struct *next; - int used; - struct pci_dev *pcidev; - unsigned short vendor; - unsigned short device; - unsigned int master; - unsigned char pci_bus; - unsigned char pci_slot; - unsigned char pci_func; - unsigned int io_addr[5]; - unsigned int irq; -}; - -struct pcilst_struct *amcc_devices; /* ptr to root list of all amcc devices */ - -/****************************************************************************/ - -void v_pci_card_list_init(unsigned short pci_vendor, char display); -void v_pci_card_list_cleanup(unsigned short pci_vendor); -struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id, - unsigned short - device_id); -int i_find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card); -struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot); - -int i_pci_card_alloc(struct pcilst_struct *amcc); -int i_pci_card_free(struct pcilst_struct *amcc); -void v_pci_card_list_display(void); -int i_pci_card_data(struct pcilst_struct *amcc, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, unsigned short *io_addr, - unsigned short *irq, unsigned short *master); - -/****************************************************************************/ - -/* build list of amcc cards in this system */ -void v_pci_card_list_init(unsigned short pci_vendor, char display) -{ - struct pci_dev *pcidev; - struct pcilst_struct *amcc, *last; - int i; - - amcc_devices = NULL; - last = NULL; - - pci_for_each_dev(pcidev) { - if (pcidev->vendor == pci_vendor) { - amcc = kzalloc(sizeof(*amcc), GFP_KERNEL); - if (amcc == NULL) - continue; - - amcc->pcidev = pcidev; - if (last) { - last->next = amcc; - } else { - amcc_devices = amcc; - } - last = amcc; - - amcc->vendor = pcidev->vendor; - amcc->device = pcidev->device; -#if 0 - amcc->master = pcidev->master; /* how get this information under 2.4 kernels? */ -#endif - amcc->pci_bus = pcidev->bus->number; - amcc->pci_slot = PCI_SLOT(pcidev->devfn); - amcc->pci_func = PCI_FUNC(pcidev->devfn); - for (i = 0; i < 5; i++) - amcc->io_addr[i] = - pcidev->resource[i].start & ~3UL; - amcc->irq = pcidev->irq; - } - } - - if (display) - v_pci_card_list_display(); -} - -/****************************************************************************/ -/* free up list of amcc cards in this system */ -void v_pci_card_list_cleanup(unsigned short pci_vendor) -{ - struct pcilst_struct *amcc, *next; - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - kfree(amcc); - } - - amcc_devices = NULL; -} - -/****************************************************************************/ -/* find first unused card with this device_id */ -struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id, - unsigned short device_id) -{ - struct pcilst_struct *amcc, *next; - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - if ((!amcc->used) && (amcc->device == device_id) - && (amcc->vendor == vendor_id)) - return amcc; - - } - - return NULL; -} - -/****************************************************************************/ -/* find card on requested position */ -int i_find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card) -{ - struct pcilst_struct *amcc, *next; - - *card = NULL; - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - if ((amcc->vendor == vendor_id) && (amcc->device == device_id) - && (amcc->pci_bus == pci_bus) - && (amcc->pci_slot == pci_slot)) { - if (!(amcc->used)) { - *card = amcc; - return 0; /* ok, card is found */ - } else { - printk - (" - \nCard on requested position is used b:s %d:%d!\n", - pci_bus, pci_slot); - return 2; /* card exist but is used */ - } - } - } - - return 1; /* no card found */ -} - -/****************************************************************************/ -/* mark card as used */ -int i_pci_card_alloc(struct pcilst_struct *amcc) -{ - if (!amcc) - return -1; - - if (amcc->used) - return 1; - amcc->used = 1; - return 0; -} - -/****************************************************************************/ -/* mark card as free */ -int i_pci_card_free(struct pcilst_struct *amcc) -{ - if (!amcc) - return -1; - - if (!amcc->used) - return 1; - amcc->used = 0; - return 0; -} - -/****************************************************************************/ -/* display list of found cards */ -void v_pci_card_list_display(void) -{ - struct pcilst_struct *amcc, *next; - - printk("List of pci cards\n"); - printk("bus:slot:func vendor device master io_amcc io_daq irq used\n"); - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - printk - ("%2d %2d %2d 0x%4x 0x%4x %3s 0x%4x 0x%4x %2d %2d\n", - amcc->pci_bus, amcc->pci_slot, amcc->pci_func, - amcc->vendor, amcc->device, amcc->master ? "yes" : "no", - amcc->io_addr[0], amcc->io_addr[2], amcc->irq, amcc->used); - - } -} - -/****************************************************************************/ -/* return all card information for driver */ -int i_pci_card_data(struct pcilst_struct *amcc, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, unsigned short *io_addr, - unsigned short *irq, unsigned short *master) -{ - int i; - - if (!amcc) - return -1; - *pci_bus = amcc->pci_bus; - *pci_slot = amcc->pci_slot; - *pci_func = amcc->pci_func; - for (i = 0; i < 5; i++) - io_addr[i] = amcc->io_addr[i]; - *irq = amcc->irq; - *master = amcc->master; - return 0; -} - -/****************************************************************************/ -/* select and alloc card */ -struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot) -{ - struct pcilst_struct *card; - - if ((pci_bus < 1) & (pci_slot < 1)) { /* use autodetection */ - card = ptr_find_free_pci_card_by_device(vendor_id, device_id); - if (card == NULL) { - printk(" - Unused card not found in system!\n"); - return NULL; - } - } else { - switch (i_find_free_pci_card_by_position(vendor_id, device_id, - pci_bus, pci_slot, - &card)) { - case 1: - printk - (" - Card not found on requested position b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - case 2: - printk - (" - Card on requested position is used b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - } - } - - if (i_pci_card_alloc(card) != 0) { - printk(" - Can't allocate card!\n"); - return NULL; - } - - return card; -} - -#endif diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c deleted file mode 100644 index a76ed2553fb..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c +++ /dev/null @@ -1,1266 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1710 | Compiler : GCC | - | Module name : hwdrv_apci1710.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1710 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ -#include "hwdrv_APCI1710.h" -#include "APCI1710_Inp_cpt.c" - -#include "APCI1710_Ssi.c" -#include "APCI1710_Tor.c" -#include "APCI1710_Ttl.c" -#include "APCI1710_Dig_io.c" -#include "APCI1710_82x54.c" -#include "APCI1710_Chrono.c" -#include "APCI1710_Pwm.c" -#include "APCI1710_INCCPT.c" - -void i_ADDI_AttachPCI1710(struct comedi_device *dev) -{ - struct comedi_subdevice *s; - int ret = 0; - int n_subdevices = 9; - - /* Update-0.7.57->0.7.68dev->n_subdevices = 9; */ - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) - return; - - /* Allocate and Initialise Timer Subdevice Structures */ - s = dev->subdevices + 0; - - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 3; - s->maxdata = 0; - s->len_chanlist = 3; - s->range_table = &range_digital; - s->insn_write = i_APCI1710_InsnWriteEnableDisableTimer; - s->insn_read = i_APCI1710_InsnReadAllTimerValue; - s->insn_config = i_APCI1710_InsnConfigInitTimer; - s->insn_bits = i_APCI1710_InsnBitsTimer; - - /* Allocate and Initialise DIO Subdevice Structures */ - s = dev->subdevices + 1; - - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 7; - s->maxdata = 1; - s->len_chanlist = 7; - s->range_table = &range_digital; - s->insn_config = i_APCI1710_InsnConfigDigitalIO; - s->insn_read = i_APCI1710_InsnReadDigitalIOChlValue; - s->insn_bits = i_APCI1710_InsnBitsDigitalIOPortOnOff; - s->insn_write = i_APCI1710_InsnWriteDigitalIOChlOnOff; - - /* Allocate and Initialise Chrono Subdevice Structures */ - s = dev->subdevices + 2; - - s->type = COMEDI_SUBD_CHRONO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 0; - s->len_chanlist = 4; - s->range_table = &range_digital; - s->insn_write = i_APCI1710_InsnWriteEnableDisableChrono; - s->insn_read = i_APCI1710_InsnReadChrono; - s->insn_config = i_APCI1710_InsnConfigInitChrono; - s->insn_bits = i_APCI1710_InsnBitsChronoDigitalIO; - - /* Allocate and Initialise PWM Subdevice Structures */ - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_PWM; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 3; - s->maxdata = 1; - s->len_chanlist = 3; - s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ - s->insn_config = i_APCI1710_InsnConfigPWM; - s->insn_read = i_APCI1710_InsnReadGetPWMStatus; - s->insn_write = i_APCI1710_InsnWritePWM; - s->insn_bits = i_APCI1710_InsnBitsReadPWMInterrupt; - - /* Allocate and Initialise TTLIO Subdevice Structures */ - s = dev->subdevices + 4; - s->type = COMEDI_SUBD_TTLIO; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 8; - s->maxdata = 1; - s->len_chanlist = 8; - s->range_table = &range_apci1710_ttl; /* to pass arguments in range */ - s->insn_config = i_APCI1710_InsnConfigInitTTLIO; - s->insn_bits = i_APCI1710_InsnBitsReadTTLIO; - s->insn_write = i_APCI1710_InsnWriteSetTTLIOChlOnOff; - s->insn_read = i_APCI1710_InsnReadTTLIOAllPortValue; - - /* Allocate and Initialise TOR Subdevice Structures */ - s = dev->subdevices + 5; - s->type = COMEDI_SUBD_TOR; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 8; - s->maxdata = 1; - s->len_chanlist = 8; - s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ - s->insn_config = i_APCI1710_InsnConfigInitTorCounter; - s->insn_read = i_APCI1710_InsnReadGetTorCounterInitialisation; - s->insn_write = i_APCI1710_InsnWriteEnableDisableTorCounter; - s->insn_bits = i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue; - - /* Allocate and Initialise SSI Subdevice Structures */ - s = dev->subdevices + 6; - s->type = COMEDI_SUBD_SSI; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 1; - s->len_chanlist = 4; - s->range_table = &range_apci1710_ssi; - s->insn_config = i_APCI1710_InsnConfigInitSSI; - s->insn_read = i_APCI1710_InsnReadSSIValue; - s->insn_bits = i_APCI1710_InsnBitsSSIDigitalIO; - - /* Allocate and Initialise PULSEENCODER Subdevice Structures */ - s = dev->subdevices + 7; - s->type = COMEDI_SUBD_PULSEENCODER; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 4; - s->maxdata = 1; - s->len_chanlist = 4; - s->range_table = &range_digital; - s->insn_config = i_APCI1710_InsnConfigInitPulseEncoder; - s->insn_write = i_APCI1710_InsnWriteEnableDisablePulseEncoder; - s->insn_bits = i_APCI1710_InsnBitsReadWritePulseEncoder; - s->insn_read = i_APCI1710_InsnReadInterruptPulseEncoder; - - /* Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures */ - s = dev->subdevices + 8; - s->type = COMEDI_SUBD_INCREMENTALCOUNTER; - s->subdev_flags = - SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 500; - s->maxdata = 1; - s->len_chanlist = 500; - s->range_table = &range_apci1710_inccpt; - s->insn_config = i_APCI1710_InsnConfigINCCPT; - s->insn_write = i_APCI1710_InsnWriteINCCPT; - s->insn_read = i_APCI1710_InsnReadINCCPT; - s->insn_bits = i_APCI1710_InsnBitsINCCPT; -} - -int i_APCI1710_Reset(struct comedi_device *dev); -void v_APCI1710_Interrupt(int irq, void *d); -/* for 1710 */ - -int i_APCI1710_Reset(struct comedi_device *dev) -{ - int ret; - unsigned int dw_Dummy; - - /*********************************/ - /* Read all module configuration */ - /*********************************/ - ret = inl(devpriv->s_BoardInfos.ui_Address + 60); - devpriv->s_BoardInfos.dw_MolduleConfiguration[0] = ret; - - ret = inl(devpriv->s_BoardInfos.ui_Address + 124); - devpriv->s_BoardInfos.dw_MolduleConfiguration[1] = ret; - - ret = inl(devpriv->s_BoardInfos.ui_Address + 188); - devpriv->s_BoardInfos.dw_MolduleConfiguration[2] = ret; - - ret = inl(devpriv->s_BoardInfos.ui_Address + 252); - devpriv->s_BoardInfos.dw_MolduleConfiguration[3] = ret; - - /* outl(0x80808082,devpriv->s_BoardInfos.ui_Address+0x60); */ - outl(0x83838383, devpriv->s_BoardInfos.ui_Address + 0x60); - - devpriv->s_BoardInfos.b_BoardVersion = 1; - - /* Enable the interrupt for the controller */ - dw_Dummy = inl(devpriv->s_BoardInfos.ui_Address + 0x38); - outl(dw_Dummy | 0x2000, devpriv->s_BoardInfos.ui_Address + 0x38); - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function's Name : __void__ v_APCI1710_InterruptFunction | -| (unsigned char b_Interrupt, __CPPARGS) | -+----------------------------------------------------------------------------+ -| Task : APCI-1710 interrupt function | -+----------------------------------------------------------------------------+ -| Input Parameters : unsigned char b_Interrupt : Interrupt number | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 : OK | -| -1 : Error | -+----------------------------------------------------------------------------+ -*/ - -void v_APCI1710_Interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - unsigned char b_ModuleCpt = 0; - unsigned char b_InterruptFlag = 0; - unsigned char b_PWMCpt = 0; - unsigned char b_TorCounterCpt = 0; - unsigned char b_PulseIncoderCpt = 0; - unsigned int ui_16BitValue; - unsigned int ul_InterruptLatchReg = 0; - unsigned int ul_LatchRegisterValue = 0; - unsigned int ul_82X54InterruptStatus; - unsigned int ul_StatusRegister; - - union str_ModuleInfo *ps_ModuleInfo; - - printk("APCI1710 Interrupt\n"); - for (b_ModuleCpt = 0; b_ModuleCpt < 4; b_ModuleCpt++, ps_ModuleInfo++) { - - /**************************/ - /* 1199/0225 to 0100/0226 */ - /**************************/ - ps_ModuleInfo = &devpriv->s_ModuleInfo[b_ModuleCpt]; - - /***********************/ - /* Test if 82X54 timer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_82X54_TIMER) { - - /* printk("TIMER Interrupt Occurred\n"); */ - ul_82X54InterruptStatus = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (64 * b_ModuleCpt)); - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if ((ul_82X54InterruptStatus & ps_ModuleInfo-> - s_82X54ModuleInfo. - b_InterruptMask) != 0) { - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = - (ul_82X54InterruptStatus & - ps_ModuleInfo->s_82X54ModuleInfo. - b_InterruptMask) << 4; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write].ul_OldCounterLatchValue = 0; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, 0); - - } /* if ((ul_82X54InterruptStatus & 0x7) != 0) */ - } /* 82X54 timer */ - - /***************************/ - /* Test if increm. counter */ - /***************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_INCREMENTAL_COUNTER) { - - ul_InterruptLatchReg = inl(devpriv->s_BoardInfos. - ui_Address + (64 * b_ModuleCpt)); - - /*********************/ - /* Test if interrupt */ - /*********************/ - - if ((ul_InterruptLatchReg & 0x22) && (ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & 0x80)) { - /************************************/ - /* Test if strobe latch I interrupt */ - /************************************/ - - if (ul_InterruptLatchReg & 2) { - ul_LatchRegisterValue = - inl(devpriv->s_BoardInfos. - ui_Address + 4 + - (64 * b_ModuleCpt)); - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 1UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - - /*************************************/ - /* Test if strobe latch II interrupt */ - /*************************************/ - - if (ul_InterruptLatchReg & 0x20) { - - ul_LatchRegisterValue = - inl(devpriv->s_BoardInfos. - ui_Address + 8 + - (64 * b_ModuleCpt)); - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 2UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - } - - ul_InterruptLatchReg = inl(devpriv->s_BoardInfos. - ui_Address + 24 + (64 * b_ModuleCpt)); - - /***************************/ - /* Test if index interrupt */ - /***************************/ - - if (ul_InterruptLatchReg & 0x8) { - ps_ModuleInfo-> - s_SiemensCounterInfo. - s_InitFlag.b_IndexInterruptOccur = 1; - - if (ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister2 & - APCI1710_INDEX_AUTO_MODE) { - - outl(ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - dw_ModeRegister1_2_3_4, - devpriv->s_BoardInfos. - ui_Address + 20 + - (64 * b_ModuleCpt)); - } - - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if ((ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_ENABLE_INDEX_INT) == - APCI1710_ENABLE_INDEX_INT) { - devpriv->s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 4UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - } - - /*****************************/ - /* Test if compare interrupt */ - /*****************************/ - - if (ul_InterruptLatchReg & 0x10) { - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if ((ps_ModuleInfo-> - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister3 & - APCI1710_ENABLE_COMPARE_INT) == - APCI1710_ENABLE_COMPARE_INT) { - devpriv->s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 8UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - } - - /*******************************************/ - /* Test if frequency measurement interrupt */ - /*******************************************/ - - if (ul_InterruptLatchReg & 0x20) { - /*******************/ - /* Read the status */ - /*******************/ - - ul_StatusRegister = inl(devpriv->s_BoardInfos. - ui_Address + 32 + (64 * b_ModuleCpt)); - - /******************/ - /* Read the value */ - /******************/ - - ul_LatchRegisterValue = - inl(devpriv->s_BoardInfos.ui_Address + - 28 + (64 * b_ModuleCpt)); - - switch ((ul_StatusRegister >> 1) & 3) { - case 0: - /*************************/ - /* Test the counter mode */ - /*************************/ - - if ((devpriv->s_ModuleInfo[b_ModuleCpt]. - s_SiemensCounterInfo. - s_ModeRegister. - s_ByteModeRegister. - b_ModeRegister1 & - APCI1710_16BIT_COUNTER) - == APCI1710_16BIT_COUNTER) { - /****************************************/ - /* Test if 16-bit counter 1 pulse occur */ - /****************************************/ - - if ((ul_LatchRegisterValue & - 0xFFFFU) != 0) { - ui_16BitValue = - (unsigned int) - ul_LatchRegisterValue - & 0xFFFFU; - ul_LatchRegisterValue = - (ul_LatchRegisterValue - & 0xFFFF0000UL) - | (0xFFFFU - - ui_16BitValue); - } - - /****************************************/ - /* Test if 16-bit counter 2 pulse occur */ - /****************************************/ - - if ((ul_LatchRegisterValue & - 0xFFFF0000UL) != - 0) { - ui_16BitValue = - (unsigned int) ( - (ul_LatchRegisterValue - >> 16) & - 0xFFFFU); - ul_LatchRegisterValue = - (ul_LatchRegisterValue - & 0xFFFFUL) | - ((0xFFFFU - - ui_16BitValue) - << 16); - } - } else { - if (ul_LatchRegisterValue != 0) { - ul_LatchRegisterValue = - 0xFFFFFFFFUL - - ul_LatchRegisterValue; - } - } - break; - - case 1: - /****************************************/ - /* Test if 16-bit counter 2 pulse occur */ - /****************************************/ - - if ((ul_LatchRegisterValue & - 0xFFFF0000UL) != 0) { - ui_16BitValue = - (unsigned int) ( - (ul_LatchRegisterValue - >> 16) & - 0xFFFFU); - ul_LatchRegisterValue = - (ul_LatchRegisterValue & - 0xFFFFUL) | ((0xFFFFU - - ui_16BitValue) - << 16); - } - break; - - case 2: - /****************************************/ - /* Test if 16-bit counter 1 pulse occur */ - /****************************************/ - - if ((ul_LatchRegisterValue & 0xFFFFU) != - 0) { - ui_16BitValue = - (unsigned int) - ul_LatchRegisterValue & - 0xFFFFU; - ul_LatchRegisterValue = - (ul_LatchRegisterValue & - 0xFFFF0000UL) | (0xFFFFU - - ui_16BitValue); - } - break; - } - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = 0x10000UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters[devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, 0); - - } - } /* Incremental counter */ - - /***************/ - /* Test if CDA */ - /***************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_CDA) { - /******************************************/ - /* Test if CDA enable and functionality 0 */ - /******************************************/ - - if ((devpriv->s_ModuleInfo[b_ModuleCpt]. - s_CDAModuleInfo. - b_CDAEnable == APCI1710_ENABLE) - && (devpriv->s_ModuleInfo[b_ModuleCpt]. - s_CDAModuleInfo.b_FctSelection == 0)) { - /****************************/ - /* Get the interrupt status */ - /****************************/ - - ul_StatusRegister = inl(devpriv->s_BoardInfos. - ui_Address + 16 + (64 * b_ModuleCpt)); - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if (ul_StatusRegister & 1) { - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 0x80000UL; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = 0; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } /* if (ul_StatusRegister & 1) */ - - } - } /* CDA */ - - /***********************/ - /* Test if PWM counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_PWM) { - for (b_PWMCpt = 0; b_PWMCpt < 2; b_PWMCpt++) { - /*************************************/ - /* Test if PWM interrupt initialised */ - /*************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModuleCpt]. - s_PWMModuleInfo. - s_PWMInfo[b_PWMCpt]. - b_InterruptEnable == APCI1710_ENABLE) { - /*****************************/ - /* Read the interrupt status */ - /*****************************/ - - ul_StatusRegister = - inl(devpriv->s_BoardInfos. - ui_Address + 16 + - (20 * b_PWMCpt) + - (64 * b_ModuleCpt)); - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if (ul_StatusRegister & 0x1) { - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = - 0x4000UL << b_PWMCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % - APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, - devpriv->tsk_Current, - 0); - - } /* if (ul_StatusRegister & 0x1) */ - } /* if (APCI1710_ENABLE) */ - } /* for (b_PWMCpt == 0; b_PWMCpt < 0; b_PWMCpt ++) */ - } /* PWM counter */ - - /***********************/ - /* Test if tor counter */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_TOR_COUNTER) { - for (b_TorCounterCpt = 0; b_TorCounterCpt < 2; - b_TorCounterCpt++) { - /*************************************/ - /* Test if tor interrupt initialised */ - /*************************************/ - - if (devpriv-> - s_ModuleInfo[b_ModuleCpt]. - s_TorCounterModuleInfo. - s_TorCounterInfo[b_TorCounterCpt]. - b_InterruptEnable == APCI1710_ENABLE) { - /*****************************/ - /* Read the interrupt status */ - /*****************************/ - - ul_StatusRegister = - inl(devpriv->s_BoardInfos. - ui_Address + 12 + - (16 * b_TorCounterCpt) + - (64 * b_ModuleCpt)); - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if (ul_StatusRegister & 0x1) { - /******************************/ - /* Read the tor counter value */ - /******************************/ - - ul_LatchRegisterValue = - inl(devpriv-> - s_BoardInfos. - ui_Address + 0 + - (16 * b_TorCounterCpt) + - (64 * b_ModuleCpt)); - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = - 0x1000UL << - b_TorCounterCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue - = ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % - APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, - devpriv->tsk_Current, - 0); - } /* if (ul_StatusRegister & 0x1) */ - } /* if (APCI1710_ENABLE) */ - } /* for (b_TorCounterCpt == 0; b_TorCounterCpt < 0; b_TorCounterCpt ++) */ - } /* Tor counter */ - - /***********************/ - /* Test if chronometer */ - /***********************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_CHRONOMETER) { - - /* printk("APCI1710 Chrono Interrupt\n"); */ - /*****************************/ - /* Read the interrupt status */ - /*****************************/ - - ul_InterruptLatchReg = inl(devpriv->s_BoardInfos. - ui_Address + 12 + (64 * b_ModuleCpt)); - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - if ((ul_InterruptLatchReg & 0x8) == 0x8) { - /****************************/ - /* Clear the interrupt flag */ - /****************************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 32 + (64 * b_ModuleCpt)); - - /***************************/ - /* Test if continuous mode */ - /***************************/ - - if (ps_ModuleInfo-> - s_ChronoModuleInfo. - b_CycleMode == APCI1710_ENABLE) { - /********************/ - /* Clear the status */ - /********************/ - - outl(0, devpriv->s_BoardInfos. - ui_Address + 36 + - (64 * b_ModuleCpt)); - } - - /*************************/ - /* Read the timing value */ - /*************************/ - - ul_LatchRegisterValue = - inl(devpriv->s_BoardInfos.ui_Address + - 4 + (64 * b_ModuleCpt)); - - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if (ps_ModuleInfo-> - s_ChronoModuleInfo.b_InterruptMask) { - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].ul_OldInterruptMask = - 0x80; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write].b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv->s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue = - ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, devpriv->tsk_Current, - 0); - - } - } - } /* Chronometer */ - - /*************************/ - /* Test if pulse encoder */ - /*************************/ - - if ((devpriv->s_BoardInfos. - dw_MolduleConfiguration[b_ModuleCpt] & - 0xFFFF0000UL) == APCI1710_PULSE_ENCODER) { - /****************************/ - /* Read the status register */ - /****************************/ - - ul_StatusRegister = inl(devpriv->s_BoardInfos. - ui_Address + 20 + (64 * b_ModuleCpt)); - - if (ul_StatusRegister & 0xF) { - for (b_PulseIncoderCpt = 0; - b_PulseIncoderCpt < 4; - b_PulseIncoderCpt++) { - /*************************************/ - /* Test if pulse encoder initialised */ - /*************************************/ - - if ((ps_ModuleInfo-> - s_PulseEncoderModuleInfo. - s_PulseEncoderInfo - [b_PulseIncoderCpt]. - b_PulseEncoderInit == 1) - && (((ps_ModuleInfo->s_PulseEncoderModuleInfo.dw_SetRegister >> b_PulseIncoderCpt) & 1) == 1) && (((ul_StatusRegister >> (b_PulseIncoderCpt)) & 1) == 1)) { - devpriv->s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldInterruptMask = - 0x100UL << - b_PulseIncoderCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - b_OldModuleMask = - 1 << b_ModuleCpt; - - devpriv-> - s_InterruptParameters. - s_FIFOInterruptParameters - [devpriv-> - s_InterruptParameters. - ui_Write]. - ul_OldCounterLatchValue - = ul_LatchRegisterValue; - - devpriv-> - s_InterruptParameters. - ul_InterruptOccur++; - - /****************************/ - /* 0899/0224 to 1199/0225 */ - /****************************/ - /* Increment the write FIFO */ - /****************************/ - - devpriv-> - s_InterruptParameters. - ui_Write = (devpriv-> - s_InterruptParameters. - ui_Write + - 1) % - APCI1710_SAVE_INTERRUPT; - - b_InterruptFlag = 1; - - /**********************/ - /* Call user function */ - /**********************/ - /* Send a signal to from kernel to user space */ - send_sig(SIGIO, - devpriv->tsk_Current, - 0); - - } - } - } - } /* pulse encoder */ - - } - return; - -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h deleted file mode 100644 index 89c99eb5228..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * 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. - */ - -#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ -#define COMEDI_SUBD_PWM 12 /* Pulse width Measurement */ -#define COMEDI_SUBD_SSI 13 /* Synchronous serial interface */ -#define COMEDI_SUBD_TOR 14 /* Tor counter */ -#define COMEDI_SUBD_CHRONO 15 /* Chrono meter */ -#define COMEDI_SUBD_PULSEENCODER 16 /* Pulse Encoder INP CPT */ -#define COMEDI_SUBD_INCREMENTALCOUNTER 17 /* Incremental Counter */ - -#define APCI1710_BOARD_NAME "apci1710" -#define APCI1710_BOARD_VENDOR_ID 0x10E8 -#define APCI1710_BOARD_DEVICE_ID 0x818F -#define APCI1710_ADDRESS_RANGE 256 -#define APCI1710_CONFIG_ADDRESS_RANGE 8 -#define APCI1710_INCREMENTAL_COUNTER 0x53430000UL -#define APCI1710_SSI_COUNTER 0x53490000UL -#define APCI1710_TTL_IO 0x544C0000UL -#define APCI1710_DIGITAL_IO 0x44490000UL -#define APCI1710_82X54_TIMER 0x49430000UL -#define APCI1710_CHRONOMETER 0x43480000UL -#define APCI1710_PULSE_ENCODER 0x495A0000UL -#define APCI1710_TOR_COUNTER 0x544F0000UL -#define APCI1710_PWM 0x50570000UL -#define APCI1710_ETM 0x45540000UL -#define APCI1710_CDA 0x43440000UL -#define APCI1710_DISABLE 0 -#define APCI1710_ENABLE 1 -#define APCI1710_SYNCHRONOUS_MODE 1 -#define APCI1710_ASYNCHRONOUS_MODE 0 - -/* MODULE INFO STRUCTURE */ - -static const struct comedi_lrange range_apci1710_ttl = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1) - } -}; - -static const struct comedi_lrange range_apci1710_ssi = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1) - } -}; - -static const struct comedi_lrange range_apci1710_inccpt = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1) - } -}; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c index 5997b2f504a..28450f65a13 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.c @@ -1,146 +1,149 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ /* + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + */ + +/* Card Specific information */ +#define APCI035_ADDRESS_RANGE 255 + +/* Timer / Watchdog Related Defines */ +#define APCI035_TCW_SYNC_ENABLEDISABLE 0 +#define APCI035_TCW_RELOAD_VALUE 4 +#define APCI035_TCW_TIMEBASE 8 +#define APCI035_TCW_PROG 12 +#define APCI035_TCW_TRIG_STATUS 16 +#define APCI035_TCW_IRQ 20 +#define APCI035_TCW_WARN_TIMEVAL 24 +#define APCI035_TCW_WARN_TIMEBASE 28 + +#define ADDIDATA_TIMER 0 +/* #define ADDIDATA_WATCHDOG 1 */ + +#define APCI035_TW1 0 +#define APCI035_TW2 32 +#define APCI035_TW3 64 +#define APCI035_TW4 96 + +#define APCI035_AI_OFFSET 0 +#define APCI035_TEMP 128 +#define APCI035_ALR_SEQ 4 +#define APCI035_START_STOP_INDEX 8 +#define APCI035_ALR_START_STOP 12 +#define APCI035_ALR_IRQ 16 +#define APCI035_EOS 20 +#define APCI035_CHAN_NO 24 +#define APCI035_CHAN_VAL 28 +#define APCI035_CONV_TIME_TIME_BASE 36 +#define APCI035_RELOAD_CONV_TIME_VAL 32 +#define APCI035_DELAY_TIME_TIME_BASE 44 +#define APCI035_RELOAD_DELAY_TIME_VAL 40 +#define ENABLE_EXT_TRIG 1 +#define ENABLE_EXT_GATE 2 +#define ENABLE_EXT_TRIG_GATE 3 + +#define ANALOG_INPUT 0 +#define TEMPERATURE 1 +#define RESISTANCE 2 + +#define ADDIDATA_GREATER_THAN_TEST 0 +#define ADDIDATA_LESS_THAN_TEST 1 + +#define APCI035_MAXVOLT 2.5 + +#define ADDIDATA_UNIPOLAR 1 +#define ADDIDATA_BIPOLAR 2 + +/* ANALOG INPUT RANGE */ +static struct comedi_lrange range_apci035_ai = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1) + } +}; - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-035 | Compiler : GCC | - | Module name : hwdrv_apci035.c | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-035 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ -#include "hwdrv_apci035.h" -static int i_WatchdogNbr = 0; -static int i_Temp = 0; +static int i_WatchdogNbr; +static int i_Temp; static int i_Flag = 1; + /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ConfigTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Watchdog | -| data[1] : Watchdog number -| data[2] : Time base Unit | -| data[3] : Reload Value | -| data[4] : External Trigger | -| 1:Enable -| 0:Disable -| data[5] :External Trigger Level -| 00 Trigger Disabled -| 01 Trigger Enabled (Low level) -| 10 Trigger Enabled (High Level) -| 11 Trigger Enabled (High/Low level) -| data[6] : External Gate | -| 1:Enable -| 0:Disable -| data[7] : External Gate level -| 00 Gate Disabled -| 01 Gate Enabled (Low level) -| 10 Gate Enabled (High Level) -| data[8] :Warning Relay -| 1: ENABLE -| 0: DISABLE -| data[9] :Warning Delay available -| data[10] :Warning Relay Time unit -| data[11] :Warning Relay Time Reload value -| data[12] :Reset Relay -| 1 : ENABLE -| 0 : DISABLE -| data[13] :Interrupt -| 1 : ENABLE -| 0 : DISABLE -| -| -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * Configures The Timer , Counter or Watchdog + * + * data[0] 0 = Configure As Timer, 1 = Configure As Watchdog + * data[1] Watchdog number + * data[2] Time base Unit + * data[3] Reload Value + * data[4] External Trigger, 1 = Enable, 0 = Disable + * data[5] External Trigger Level + * 00 = Trigger Disabled + * 01 = Trigger Enabled (Low level) + * 10 = Trigger Enabled (High Level) + * 11 = Trigger Enabled (High/Low level) + * data[6] External Gate, 1 = Enable, 0 = Disable + * data[7] External Gate level + * 00 = Gate Disabled + * 01 = Gate Enabled (Low level) + * 10 = Gate Enabled (High Level) + * data[8] Warning Relay, 1 = Enable, 0 = Disable + * data[9] Warning Delay available + * data[10] Warning Relay Time unit + * data[11] Warning Relay Time Reload value + * data[12] Reset Relay, 1 = Enable, 0 = Disable + * data[13] Interrupt, 1 = Enable, 0 = Disable + */ +static int apci035_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int ui_Status = 0; - unsigned int ui_Command = 0; - unsigned int ui_Mode = 0; + struct addi_private *devpriv = dev->private; + unsigned int ui_Status; + unsigned int ui_Command; + unsigned int ui_Mode; + i_Temp = 0; devpriv->tsk_Current = current; devpriv->b_TimerSelectMode = data[0]; i_WatchdogNbr = data[1]; - if (data[0] == 0) { + if (data[0] == 0) ui_Mode = 2; - } else { + else ui_Mode = 0; - } -/* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); */ + ui_Command = 0; -/* ui_Command = ui_Command & 0xFFFFF9FEUL; */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/************************/ -/* Set the reload value */ -/************************/ + + /* Set the reload value */ outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4); -/*********************/ -/* Set the time unit */ -/*********************/ + + /* Set the time unit */ outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8); if (data[0] == ADDIDATA_TIMER) { - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -148,101 +151,82 @@ int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subde /* - Disable the reset */ /* - Enable the timer mode */ /* - Set the timer mode */ - /******************************/ ui_Command = (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; - } /* if (data[0] == ADDIDATA_TIMER) */ - else { - if (data[0] == ADDIDATA_WATCHDOG) { + } else if (data[0] == ADDIDATA_WATCHDOG) { - /******************************/ - /* Set the mode : */ - /* - Disable the hardware */ - /* - Disable the counter mode */ - /* - Disable the warning */ - /* - Disable the reset */ - /* - Disable the timer mode */ - /******************************/ + /* Set the mode : */ + /* - Disable the hardware */ + /* - Disable the counter mode */ + /* - Disable the warning */ + /* - Disable the reset */ + /* - Disable the timer mode */ - ui_Command = ui_Command & 0xFFF819E2UL; + ui_Command = ui_Command & 0xFFF819E2UL; - } else { - printk("\n The parameter for Timer/watchdog selection is in error\n"); - return -EINVAL; - } + } else { + dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n"); + return -EINVAL; } + outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/********************************/ -/* Disable the hardware trigger */ -/********************************/ + + /* Disable the hardware trigger */ ui_Command = ui_Command & 0xFFFFF89FUL; if (data[4] == ADDIDATA_ENABLE) { - /**********************************/ + /* Set the hardware trigger level */ - /**********************************/ ui_Command = ui_Command | (data[5] << 5); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*****************************/ -/* Disable the hardware gate */ -/*****************************/ + + /* Disable the hardware gate */ ui_Command = ui_Command & 0xFFFFF87FUL; if (data[6] == ADDIDATA_ENABLE) { -/*******************************/ -/* Set the hardware gate level */ -/*******************************/ + + /* Set the hardware gate level */ ui_Command = ui_Command | (data[7] << 7); } outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - ui_Command = 0; + ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*******************************/ -/* Disable the hardware output */ -/*******************************/ + + /* Disable the hardware output */ ui_Command = ui_Command & 0xFFFFF9FBUL; -/*********************************/ -/* Set the hardware output level */ -/*********************************/ + + /* Set the hardware output level */ ui_Command = ui_Command | (data[8] << 2); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); if (data[9] == ADDIDATA_ENABLE) { - /************************/ + /* Set the reload value */ - /************************/ outl(data[11], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24); - /**********************/ + /* Set the time unite */ - /**********************/ outl(data[10], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28); } - ui_Command = 0; ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*******************************/ + /* Disable the hardware output */ - /*******************************/ ui_Command = ui_Command & 0xFFFFF9F7UL; - /*********************************/ + /* Set the hardware output level */ - /*********************************/ ui_Command = ui_Command | (data[12] << 3); outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /*************************************/ - /** Enable the watchdog interrupt **/ - /*************************************/ - ui_Command = 0; + + /* Enable the watchdog interrupt */ ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); -/*******************************/ -/* Set the interrupt selection */ -/*******************************/ + + /* Set the interrupt selection */ ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1); @@ -252,78 +236,63 @@ int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subde } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_StartStopWriteTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 - Stop Selected Timer/Watchdog | -| 1 - Start Selected Timer/Watchdog | -| 2 - Trigger Selected Timer/Watchdog | -| 3 - Stop All Timer/Watchdog | -| 4 - Start All Timer/Watchdog | -| 5 - Trigger All Timer/Watchdog | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) + * Start / Stop The Selected Timer , or Watchdog + * + * data[0] + * 0 - Stop Selected Timer/Watchdog + * 1 - Start Selected Timer/Watch*dog + * 2 - Trigger Selected Timer/Watchdog + * 3 - Stop All Timer/Watchdog + * 4 - Start All Timer/Watchdog + * 5 - Trigger All Timer/Watchdog + */ +static int apci035_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int ui_Command = 0; - int i_Count = 0; + struct addi_private *devpriv = dev->private; + unsigned int ui_Command; + int i_Count; + if (data[0] == 1) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /**********************/ + /* Start the hardware */ - /**********************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[0]==1) */ + } if (data[0] == 2) { ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - /***************************/ + /* Set the trigger command */ - /***************************/ ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); } - if (data[0] == 0) /* Stop The Watchdog */ - { + if (data[0] == 0) { /* Stop The Watchdog */ ui_Command = 0; -/* -* ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); -* ui_Command = ui_Command & 0xFFFFF9FEUL; -*/ + /* + * ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); + * ui_Command = ui_Command & 0xFFFFF9FEUL; + */ outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); - } /* if (data[1]==0) */ - if (data[0] == 3) /* stop all Watchdogs */ - { + } + if (data[0] == 3) { + /* stop all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x2UL; - } else { + else ui_Command = 0x10UL; - } + i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + @@ -331,30 +300,29 @@ int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, } } - if (data[0] == 4) /* start all Watchdogs */ - { + if (data[0] == 4) { + /* start all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x1UL; - } else { + else ui_Command = 0x8UL; - } + i_WatchdogNbr = i_Count; outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } } - if (data[0] == 5) /* trigger all Watchdogs */ - { + if (data[0] == 5) { + /* trigger all Watchdogs */ ui_Command = 0; for (i_Count = 1; i_Count <= 4; i_Count++) { - if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) ui_Command = 0x4UL; - } else { + else ui_Command = 0x20UL; - } i_WatchdogNbr = i_Count; outl(ui_Command, @@ -367,101 +335,61 @@ int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ReadTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : software trigger status -| data[1] : hardware trigger status -| data[2] : Software clear status -| data[3] : Overflow status -| data[4] : Timer actual value -| - -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * Read The Selected Timer , Counter or Watchdog + * + * data[0] software trigger status + * data[1] hardware trigger status + * data[2] Software clear status + * data[3] Overflow status + * data[4] Timer actual value + */ +static int apci035_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int ui_Status = 0; /* Status register */ + struct addi_private *devpriv = dev->private; + unsigned int ui_Status; /* Status register */ + i_WatchdogNbr = insn->unused[0]; - /******************/ /* Get the status */ - /******************/ - ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); - /***********************************/ /* Get the software trigger status */ - /***********************************/ - data[0] = ((ui_Status >> 1) & 1); - /***********************************/ + /* Get the hardware trigger status */ - /***********************************/ data[1] = ((ui_Status >> 2) & 1); - /*********************************/ + /* Get the software clear status */ - /*********************************/ data[2] = ((ui_Status >> 3) & 1); - /***************************/ + /* Get the overflow status */ - /***************************/ data[3] = ((ui_Status >> 0) & 1); - if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { + if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ConfigAnalogInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Analog Input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| data[0] : Warning delay value -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * Configures The Analog Input Subdevice + * + * data[0] Warning delay value + */ +static int apci035_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; + devpriv->tsk_Current = current; outl(0x200 | 0, devpriv->iobase + 128 + 0x4); outl(0, devpriv->iobase + 128 + 0); -/********************************/ -/* Initialise the warning value */ -/********************************/ + + /* Initialise the warning value */ outl(0x300 | 0, devpriv->iobase + 128 + 0x4); outl((data[0] << 8), devpriv->iobase + 128 + 0); outl(0x200000UL, devpriv->iobase + 128 + 12); @@ -470,137 +398,88 @@ int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevi } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_ReadAnalogInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -| data[0] : Digital Value Of Input | -| | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI035_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * Read value of the selected channel + * + * data[0] Digital Value Of Input + */ +static int apci035_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int ui_CommandRegister = 0; -/******************/ -/* Set the start */ -/******************/ + struct addi_private *devpriv = dev->private; + unsigned int ui_CommandRegister; + + /* Set the start */ ui_CommandRegister = 0x80000; - /******************************/ + /* Write the command register */ - /******************************/ outl(ui_CommandRegister, devpriv->iobase + 128 + 8); -/***************************************/ -/* Read the digital value of the input */ -/***************************************/ + /* Read the digital value of the input */ data[0] = inl(devpriv->iobase + 128 + 28); return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI035_Reset(struct comedi_device *dev) | -| | -+----------------------------------------------------------------------------+ -| Task :Resets the registers of the card | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI035_Reset(struct comedi_device *dev) +static int apci035_reset(struct comedi_device *dev) { - int i_Count = 0; + struct addi_private *devpriv = dev->private; + int i_Count; + for (i_Count = 1; i_Count <= 4; i_Count++) { i_WatchdogNbr = i_Count; - outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); /* stop all timers */ + + /* stop all timers */ + outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); } outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ return 0; } -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI035_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt processing Routine | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI035_Interrupt(int irq, void *d) +static void apci035_interrupt(int irq, void *d) { struct comedi_device *dev = d; - unsigned int ui_StatusRegister1 = 0; - unsigned int ui_StatusRegister2 = 0; - unsigned int ui_ReadCommand = 0; - unsigned int ui_ChannelNumber = 0; - unsigned int ui_DigitalTemperature = 0; + struct addi_private *devpriv = dev->private; + unsigned int ui_StatusRegister1; + unsigned int ui_StatusRegister2; + unsigned int ui_ReadCommand; + unsigned int ui_ChannelNumber; + unsigned int ui_DigitalTemperature; + if (i_Temp == 1) { i_WatchdogNbr = i_Flag; i_Flag = i_Flag + 1; } - /**************************************/ + /* Read the interrupt status register of temperature Warning */ - /**************************************/ ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16); - /**************************************/ - /* Read the interrupt status register for Watchdog/timer */ - /**************************************/ + /* Read the interrupt status register for Watchdog/timer */ ui_StatusRegister2 = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); - if ((((ui_StatusRegister1) & 0x8) == 0x8)) /* Test if warning relay interrupt */ - { - /**********************************/ + /* Test if warning relay interrupt */ + if ((((ui_StatusRegister1) & 0x8) == 0x8)) { + /* Disable the temperature warning */ - /**********************************/ ui_ReadCommand = inl(devpriv->iobase + 128 + 12); ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL; outl(ui_ReadCommand, devpriv->iobase + 128 + 12); - /***************************/ + /* Read the channel number */ - /***************************/ ui_ChannelNumber = inl(devpriv->iobase + 128 + 60); - /**************************************/ + /* Read the digital temperature value */ - /**************************************/ ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } /* if (((ui_StatusRegister1 & 0x8) == 0x8)) */ - else { - if ((ui_StatusRegister2 & 0x1) == 0x1) { - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - } - } /* else if (((ui_StatusRegister1 & 0x8) == 0x8)) */ + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + + } else if ((ui_StatusRegister2 & 0x1) == 0x1) { + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + } return; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h deleted file mode 100644 index 3c700c7bf81..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci035.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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. - */ - -/* Card Specific information */ -#define APCI035_BOARD_VENDOR_ID 0x15B8 -#define APCI035_ADDRESS_RANGE 255 - -/* ANALOG INPUT RANGE */ -static struct comedi_lrange range_apci035_ai = { 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -/* Timer / Watchdog Related Defines */ -#define APCI035_TCW_SYNC_ENABLEDISABLE 0 -#define APCI035_TCW_RELOAD_VALUE 4 -#define APCI035_TCW_TIMEBASE 8 -#define APCI035_TCW_PROG 12 -#define APCI035_TCW_TRIG_STATUS 16 -#define APCI035_TCW_IRQ 20 -#define APCI035_TCW_WARN_TIMEVAL 24 -#define APCI035_TCW_WARN_TIMEBASE 28 - -#define ADDIDATA_TIMER 0 -/* #define ADDIDATA_WATCHDOG 1 */ - -#define APCI035_TW1 0 -#define APCI035_TW2 32 -#define APCI035_TW3 64 -#define APCI035_TW4 96 - -#define APCI035_AI_OFFSET 0 -#define APCI035_TEMP 128 -#define APCI035_ALR_SEQ 4 -#define APCI035_START_STOP_INDEX 8 -#define APCI035_ALR_START_STOP 12 -#define APCI035_ALR_IRQ 16 -#define APCI035_EOS 20 -#define APCI035_CHAN_NO 24 -#define APCI035_CHAN_VAL 28 -#define APCI035_CONV_TIME_TIME_BASE 36 -#define APCI035_RELOAD_CONV_TIME_VAL 32 -#define APCI035_DELAY_TIME_TIME_BASE 44 -#define APCI035_RELOAD_DELAY_TIME_VAL 40 -#define ENABLE_EXT_TRIG 1 -#define ENABLE_EXT_GATE 2 -#define ENABLE_EXT_TRIG_GATE 3 - -#define ANALOG_INPUT 0 -#define TEMPERATURE 1 -#define RESISTANCE 2 - -#define ADDIDATA_GREATER_THAN_TEST 0 -#define ADDIDATA_LESS_THAN_TEST 1 - -#define APCI035_MAXVOLT 2.5 - -#define ADDIDATA_UNIPOLAR 1 -#define ADDIDATA_BIPOLAR 2 - -/* ADDIDATA Enable Disable */ -#define ADDIDATA_ENABLE 1 -#define ADDIDATA_DISABLE 0 - -/* Hardware Layer functions for Apci035 */ - -/* TIMER */ -/* timer value is passed as u seconds */ -int i_APCI035_ConfigTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI035_StartStopWriteTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI035_ReadTimerWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* Temperature Related Defines (Analog Input Subdevice) */ - -int i_APCI035_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI035_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* Interrupt */ -static void v_APCI035_Interrupt(int irq, void *d); - -/* Reset functions */ -int i_APCI035_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c deleted file mode 100644 index bab7b61a53b..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.c +++ /dev/null @@ -1,287 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1032 | Compiler : GCC | - | Module name : hwdrv_apci1032.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1032 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ -#include "hwdrv_apci1032.h" -#include <linux/delay.h> - -static unsigned int ui_InterruptStatus; - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1032_ConfigDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures the digital input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 1 Enable Digital Input Interrupt | -| 0 Disable Digital Input Interrupt | -| data[1] : 0 ADDIDATA Interrupt OR LOGIC | -| : 1 ADDIDATA Interrupt AND LOGIC | -| data[2] : Interrupt mask for the mode 1 | -| data[3] : Interrupt mask for the mode 2 | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1032_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_TmpValue; - - unsigned int ul_Command1 = 0; - unsigned int ul_Command2 = 0; - devpriv->tsk_Current = current; - - /*******************************/ - /* Set the digital input logic */ - /*******************************/ - if (data[0] == ADDIDATA_ENABLE) { - ul_Command1 = ul_Command1 | data[2]; - ul_Command2 = ul_Command2 | data[3]; - outl(ul_Command1, - devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE1); - outl(ul_Command2, - devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE2); - if (data[1] == ADDIDATA_OR) { - outl(0x4, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - ui_TmpValue = - inl(devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - } /* if (data[1] == ADDIDATA_OR) */ - else - outl(0x6, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - /* else if(data[1] == ADDIDATA_OR) */ - } /* if( data[0] == ADDIDATA_ENABLE) */ - else { - ul_Command1 = ul_Command1 & 0xFFFF0000; - ul_Command2 = ul_Command2 & 0xFFFF0000; - outl(ul_Command1, - devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE1); - outl(ul_Command2, - devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE2); - outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - } /* else if ( data[0] == ADDIDATA_ENABLE) */ - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1032_Read1DigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the digital input | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1032_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_TmpValue = 0; - unsigned int ui_Channel; - ui_Channel = CR_CHAN(insn->chanspec); - if (ui_Channel <= 31) { - ui_TmpValue = (unsigned int) inl(devpriv->iobase + APCI1032_DIGITAL_IP); -/* -* since only 1 channel reqd to bring it to last bit it is rotated 8 -* +(chan - 1) times then ANDed with 1 for last bit. -*/ - *data = (ui_TmpValue >> ui_Channel) & 0x1; - } /* if(ui_Channel >= 0 && ui_Channel <=31) */ - else { - /* comedi_error(dev," \n chan spec wrong\n"); */ - return -EINVAL; /* "sorry channel spec wrong " */ - } /* else if(ui_Channel >= 0 && ui_Channel <=31) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1032_ReadMoreDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the Requested digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To be Read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1032_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_PortValue = data[0]; - unsigned int ui_Mask = 0; - unsigned int ui_NoOfChannels; - - ui_NoOfChannels = CR_CHAN(insn->chanspec); - if (data[1] == 0) { - *data = (unsigned int) inl(devpriv->iobase + APCI1032_DIGITAL_IP); - switch (ui_NoOfChannels) { - case 2: - ui_Mask = 3; - *data = (*data >> (2 * ui_PortValue)) & ui_Mask; - break; - case 4: - ui_Mask = 15; - *data = (*data >> (4 * ui_PortValue)) & ui_Mask; - break; - case 8: - ui_Mask = 255; - *data = (*data >> (8 * ui_PortValue)) & ui_Mask; - break; - case 16: - ui_Mask = 65535; - *data = (*data >> (16 * ui_PortValue)) & ui_Mask; - break; - case 31: - break; - default: - /* comedi_error(dev," \nchan spec wrong\n"); */ - return -EINVAL; /* "sorry channel spec wrong " */ - break; - } /* switch(ui_NoOfChannels) */ - } /* if(data[1]==0) */ - else { - if (data[1] == 1) - *data = ui_InterruptStatus; - /* if(data[1]==1) */ - } /* else if(data[1]==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1032_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler for the interruptible digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1032_Interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - - unsigned int ui_Temp; - /* disable the interrupt */ - ui_Temp = inl(devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - outl(ui_Temp & APCI1032_DIGITAL_IP_INTERRUPT_DISABLE, - devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); - ui_InterruptStatus = - inl(devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_STATUS); - ui_InterruptStatus = ui_InterruptStatus & 0X0000FFFF; - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - outl(ui_Temp, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); /* enable the interrupt */ - return; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1032_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1032_Reset(struct comedi_device *dev) -{ - outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_IRQ); /* disable the interrupts */ - inl(devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */ - outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */ - outl(0x0, devpriv->iobase + APCI1032_DIGITAL_IP_INTERRUPT_MODE2); - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h deleted file mode 100644 index 7114acb4bd2..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1032.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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. - */ - -/********* Definitions for APCI-1032 card *****/ - -#define APCI1032_BOARD_VENDOR_ID 0x15B8 -#define APCI1032_ADDRESS_RANGE 20 -/* DIGITAL INPUT DEFINE */ - -#define APCI1032_DIGITAL_IP 0 -#define APCI1032_DIGITAL_IP_INTERRUPT_MODE1 4 -#define APCI1032_DIGITAL_IP_INTERRUPT_MODE2 8 -#define APCI1032_DIGITAL_IP_IRQ 16 - -/* Digital Input IRQ Function Selection */ -#define ADDIDATA_OR 0 -#define ADDIDATA_AND 1 - -/* Digital Input Interrupt Status */ -#define APCI1032_DIGITAL_IP_INTERRUPT_STATUS 12 - -/* Digital Input Interrupt Enable Disable. */ -#define APCI1032_DIGITAL_IP_INTERRUPT_ENABLE 0x4 -#define APCI1032_DIGITAL_IP_INTERRUPT_DISABLE 0xFFFFFFFB - -/* ADDIDATA Enable Disable */ - -#define ADDIDATA_ENABLE 1 -#define ADDIDATA_DISABLE 0 - -/* Hardware Layer functions for Apci1032 */ - -/* -* DI for di read -*/ - -int i_APCI1032_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1032_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI1032_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* Interrupt functions..... */ - -static void v_APCI1032_Interrupt(int irq, void *d); -/* Reset */ -int i_APCI1032_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c index 62f421a06f0..a633957890d 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c @@ -1,159 +1,173 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. +/* + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + */ + +/* Card Specific information */ +#define APCI1500_ADDRESS_RANGE 4 + +/* DIGITAL INPUT-OUTPUT DEFINE */ + +#define APCI1500_DIGITAL_OP 2 +#define APCI1500_DIGITAL_IP 0 +#define APCI1500_AND 2 +#define APCI1500_OR 4 +#define APCI1500_OR_PRIORITY 6 +#define APCI1500_CLK_SELECT 0 +#define COUNTER1 0 +#define COUNTER2 1 +#define COUNTER3 2 +#define APCI1500_COUNTER 0x20 +#define APCI1500_TIMER 0 +#define APCI1500_WATCHDOG 0 +#define APCI1500_SINGLE 0 +#define APCI1500_CONTINUOUS 0x80 +#define APCI1500_DISABLE 0 +#define APCI1500_ENABLE 1 +#define APCI1500_SOFTWARE_TRIGGER 0x4 +#define APCI1500_HARDWARE_TRIGGER 0x10 +#define APCI1500_SOFTWARE_GATE 0 +#define APCI1500_HARDWARE_GATE 0x8 +#define START 0 +#define STOP 1 +#define TRIGGER 2 -@endverbatim -*/ /* + * Zillog I/O enumeration + */ +enum { + APCI1500_Z8536_PORT_C, + APCI1500_Z8536_PORT_B, + APCI1500_Z8536_PORT_A, + APCI1500_Z8536_CONTROL_REGISTER +}; - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1500 | Compiler : GCC | - | Module name : hwdrv_apci1500.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1500 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ -#include "hwdrv_apci1500.h" - -static int i_TimerCounter1Init = 0; -static int i_TimerCounter2Init = 0; -static int i_WatchdogCounter3Init = 0; -static int i_Event1Status = 0, i_Event2Status = 0; -static int i_TimerCounterWatchdogInterrupt = 0; -static int i_Logic = 0, i_CounterLogic = 0; -static int i_InterruptMask = 0; -static int i_InputChannel = 0; -static int i_TimerCounter1Enabled = 0, i_TimerCounter2Enabled = 0, - i_WatchdogCounter3Enabled = 0; +/* + * Z8536 CIO Internal Address + */ +enum { + APCI1500_RW_MASTER_INTERRUPT_CONTROL, + APCI1500_RW_MASTER_CONFIGURATION_CONTROL, + APCI1500_RW_PORT_A_INTERRUPT_CONTROL, + APCI1500_RW_PORT_B_INTERRUPT_CONTROL, + APCI1500_RW_TIMER_COUNTER_INTERRUPT_VECTOR, + APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, + APCI1500_RW_PORT_C_DATA_DIRECTION, + APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL, + + APCI1500_RW_PORT_A_COMMAND_AND_STATUS, + APCI1500_RW_PORT_B_COMMAND_AND_STATUS, + APCI1500_RW_CPT_TMR1_CMD_STATUS, + APCI1500_RW_CPT_TMR2_CMD_STATUS, + APCI1500_RW_CPT_TMR3_CMD_STATUS, + APCI1500_RW_PORT_A_DATA, + APCI1500_RW_PORT_B_DATA, + APCI1500_RW_PORT_C_DATA, + + APCI1500_R_CPT_TMR1_VALUE_HIGH, + APCI1500_R_CPT_TMR1_VALUE_LOW, + APCI1500_R_CPT_TMR2_VALUE_HIGH, + APCI1500_R_CPT_TMR2_VALUE_LOW, + APCI1500_R_CPT_TMR3_VALUE_HIGH, + APCI1500_R_CPT_TMR3_VALUE_LOW, + APCI1500_RW_CPT_TMR1_TIME_CST_HIGH, + APCI1500_RW_CPT_TMR1_TIME_CST_LOW, + APCI1500_RW_CPT_TMR2_TIME_CST_HIGH, + APCI1500_RW_CPT_TMR2_TIME_CST_LOW, + APCI1500_RW_CPT_TMR3_TIME_CST_HIGH, + APCI1500_RW_CPT_TMR3_TIME_CST_LOW, + APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION, + APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION, + APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION, + APCI1500_R_CURRENT_VECTOR, + + APCI1500_RW_PORT_A_SPECIFICATION, + APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION, + APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY, + APCI1500_RW_PORT_A_DATA_DIRECTION, + APCI1500_RW_PORT_A_SPECIAL_IO_CONTROL, + APCI1500_RW_PORT_A_PATTERN_POLARITY, + APCI1500_RW_PORT_A_PATTERN_TRANSITION, + APCI1500_RW_PORT_A_PATTERN_MASK, + + APCI1500_RW_PORT_B_SPECIFICATION, + APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION, + APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY, + APCI1500_RW_PORT_B_DATA_DIRECTION, + APCI1500_RW_PORT_B_SPECIAL_IO_CONTROL, + APCI1500_RW_PORT_B_PATTERN_POLARITY, + APCI1500_RW_PORT_B_PATTERN_TRANSITION, + APCI1500_RW_PORT_B_PATTERN_MASK +}; + +static int i_TimerCounter1Init; +static int i_TimerCounter2Init; +static int i_WatchdogCounter3Init; +static int i_Event1Status, i_Event2Status; +static int i_TimerCounterWatchdogInterrupt; +static int i_Logic, i_CounterLogic; +static int i_InterruptMask; +static int i_InputChannel; +static int i_TimerCounter1Enabled, i_TimerCounter2Enabled, + i_WatchdogCounter3Enabled; /* - +----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigDigitalInputEvent | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : An event can be generated for each port. | -| The first event is related to the first 8 channels | -| (port 1) and the second to the following 6 channels | -| (port 2). An interrupt is generated when one or both | -| events have occurred | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] :Number of the input port on | -| which the event will take place | -| (1 or 2) -| data[1] : The event logic for port 1 has | -| three possibilities | -| :0 APCI1500_AND :This logic | -| links | -| the inputs | -| with an AND | -| logic. | -| 1 APCI1500_OR :This logic | -| links | -| the inputs | -| with a | -| OR logic. | -| 2 APCI1500_OR_PRIORITY | -| :This logic | -| links | -| the inputs | -| with a | -| priority | -| OR logic. | -| Input 1 | -| has the | -| highest | -| priority | -| level and | -| input 8 | -| the smallest| -| For the second port the user has| -| 1 possibility: | -| APCI1500_OR :This logic | -| links | -| the inputs | -| with a | -| polarity | -| OR logic | -| data[2] : These 8-character word for port1| -| and 6-character word for port 2 | -| give the mask of the event. | -| Each place gives the state | -| of the input channels and can | -| have one of these six characters| -| | -| 0 : This input must be on 0 | -| 1 : This input must be on 1 | -| 2 : This input reacts to | -| a falling edge | -| 3 : This input reacts to a | -| rising edge | -| 4 : This input reacts to both edges | -| -| 5 : This input is not | -| used for event | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * An event can be generated for each port. The first event is related to the + * first 8 channels (port 1) and the second to the following 6 channels (port 2) + * An interrupt is generated when one or both events have occurred. + * + * data[0] Number of the input port on which the event will take place (1 or 2) + * data[1] The event logic for port 1 has three possibilities: + * APCI1500_AND This logic links the inputs with an AND logic. + * APCI1500_OR This logic links the inputs with a OR logic. + * APCI1500_OR_PRIORITY This logic links the inputs with a priority OR + * logic. Input 1 has the highest priority level + * and input 8 the smallest. + * For the second port the user has 1 possibility: + * APCI1500_OR This logic links the inputs with a polarity OR logic + * data[2] These 8-character word for port1 and 6-character word for port 2 + * give the mask of the event. Each place gives the state of the input + * channels and can have one of these six characters + * 0 This input must be on 0 + * 1 This input must be on 1 + * 2 This input reacts to a falling edge + * 3 This input reacts to a rising edge + * 4 This input reacts to both edges + * 5 This input is not used for event + */ +static int apci1500_di_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0; int i_MaxChannel = 0, i_Count = 0, i_EventMask = 0; int i_PatternTransitionCount = 0, i_RegValue; int i; - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Disables the main interrupt on the board */ - /**********************************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if (data[0] == 1) { @@ -164,7 +178,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, i_MaxChannel = 6; } /* if(data[0]==2) */ else { - printk("\nThe specified port event does not exist\n"); + dev_warn(dev->hw_dev, + "The specified port event does not exist\n"); return -EINVAL; } /* else if(data[0]==2) */ } /* else if (data[0] == 1) */ @@ -179,7 +194,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, data[1] = APCI1500_OR_PRIORITY; break; default: - printk("\nThe specified interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The specified interrupt logic does not exist\n"); return -EINVAL; } /* switch(data[1]); */ @@ -223,37 +239,30 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, case 5: break; default: - printk("\nThe option indicated in the event mask does not exist\n"); + dev_warn(dev->hw_dev, + "The option indicated in the event mask does not exist\n"); return -EINVAL; } /* switch(i_EventMask) */ } /* for (i_Count = i_MaxChannel; i_Count >0;i_Count --) */ if (data[0] == 1) { - /****************************/ /* Test the interrupt logic */ - /****************************/ if (data[1] == APCI1500_AND || data[1] == APCI1500_OR || data[1] == APCI1500_OR_PRIORITY) { - /**************************************/ /* Tests if a transition was declared */ /* for a OR PRIORITY logic */ - /**************************************/ if (data[1] == APCI1500_OR_PRIORITY && i_PatternTransition != 0) { - /********************************************/ - /* Transition error on an OR PRIORITY logic */ - /********************************************/ - printk("\nTransition error on an OR PRIORITY logic\n"); + dev_warn(dev->hw_dev, + "Transition error on an OR PRIORITY logic\n"); return -EINVAL; } /* if (data[1]== APCI1500_OR_PRIORITY && i_PatternTransition != 0) */ - /*************************************/ /* Tests if more than one transition */ /* was declared for an AND logic */ - /*************************************/ if (data[1] == APCI1500_AND) { for (i_Count = 0; i_Count < 8; i_Count++) { @@ -265,29 +274,21 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, } /* for (i_Count = 0; i_Count < 8; i_Count++) */ if (i_PatternTransitionCount > 1) { - /****************************************/ - /* Transition error on an AND logic */ - /****************************************/ - printk("\n Transition error on an AND logic\n"); + dev_warn(dev->hw_dev, + "Transition error on an AND logic\n"); return -EINVAL; } /* if (i_PatternTransitionCount > 1) */ } /* if (data[1]== APCI1500_AND) */ - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the polarity register of port 1 */ - /**********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -295,20 +296,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the pattern mask register of */ /* port 1 */ - /*********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_MASK, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternMask, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************/ /* Selects the pattern transition register */ /* of port 1 */ - /********************************************/ outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -316,10 +313,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 1 */ - /******************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -327,17 +322,13 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 1 */ - /******************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Port A new mode */ - /**********************/ i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9; outb(i_RegValue, @@ -346,53 +337,40 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, i_Event1Status = 1; - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ else { - printk("\nThe choice for interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The choice for interrupt logic does not exist\n"); return -EINVAL; } /* else }// if(data[1]==APCI1500_AND||data[1]==APCI1500_OR||data[1]==APCI1500_OR_PRIORITY) */ } /* if (data[0]== 1) */ - /************************************/ /* Test if event setting for port 2 */ - /************************************/ if (data[0] == 2) { - /************************/ /* Test the event logic */ - /************************/ if (data[1] == APCI1500_OR) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the mode specification mask */ /* register of port B */ - /****************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -400,10 +378,8 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port B */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -412,37 +388,29 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************/ /* Selects error channels 1 and 2 */ - /**********************************/ i_PatternMask = (i_PatternMask | 0xC0); i_PatternPolarity = (i_PatternPolarity | 0xC0); i_PatternTransition = (i_PatternTransition | 0xC0); - /**********************************************/ /* Selects the polarity register of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternPolarity, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the pattern transition register */ /* of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_PatternTransition, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Selects the pattern Mask register */ /* of port 2 */ - /**********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_MASK, devpriv->iobase + @@ -451,20 +419,16 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 2 */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************/ /* Selects the mode specification mask */ /* register of port 2 */ - /******************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -474,23 +438,20 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); i_Event2Status = 1; - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if (data[1] == APCI1500_OR) */ else { - printk("\nThe choice for interrupt logic does not exist\n"); + dev_warn(dev->hw_dev, + "The choice for interrupt logic does not exist\n"); return -EINVAL; } /* elseif (data[1] == APCI1500_OR) */ } /* if(data[0]==2) */ @@ -499,78 +460,46 @@ static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_StartStopInputEvent | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Allows or disallows a port event | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -| data[0] :0 Start input event -| 1 Stop input event -| data[1] :No of port (1 or 2) -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Allows or disallows a port event + * + * data[0] 0 = Start input event, 1 = Stop input event + * data[1] Number of port (1 or 2) + */ +static int apci1500_di_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; int i_Event1InterruptStatus = 0, i_Event2InterruptStatus = 0, i_RegValue; + switch (data[0]) { case START: - /*************************/ /* Tests the port number */ - /*************************/ if (data[1] == 1 || data[1] == 2) { - /***************************/ /* Test if port 1 selected */ - /***************************/ if (data[1] == 1) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event1Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 1 */ - /***************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Allows the pattern interrupt */ - /*************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -583,185 +512,142 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(i_Event1Status==1) */ else { - printk("\nEvent 1 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 1 not initialised\n"); return -EINVAL; } /* else if(i_Event1Status==1) */ } /* if (data[1]==1) */ if (data[1] == 2) { if (i_Event2Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 2 */ - /***************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Allows the pattern interrupt */ - /*************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 1; } /* if(i_Event2Status==1) */ else { - printk("\nEvent 2 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 2 not initialised\n"); return -EINVAL; } /* else if(i_Event2Status==1) */ } /* if(data[1]==2) */ } /* if (data[1] == 1 || data[0] == 2) */ else { - printk("\nThe port parameter is in error\n"); + dev_warn(dev->hw_dev, + "The port parameter is in error\n"); return -EINVAL; } /* else if (data[1] == 1 || data[0] == 2) */ break; case STOP: - /*************************/ /* Tests the port number */ - /*************************/ if (data[1] == 1 || data[1] == 2) { - /***************************/ /* Test if port 1 selected */ - /***************************/ if (data[1] == 1) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event1Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port A */ - /******************/ outb(0xF0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 1 */ - /***************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Inhibits the pattern interrupt */ - /*************************************/ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port A */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event1InterruptStatus = 0; } /* if(i_Event1Status==1) */ else { - printk("\nEvent 1 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 1 not initialised\n"); return -EINVAL; } /* else if(i_Event1Status==1) */ } /* if (data[1]==1) */ if (data[1] == 2) { - /*****************************/ /* Test if event initialised */ - /*****************************/ if (i_Event2Status == 1) { - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************/ /* Disable Port B */ - /******************/ outb(0x74, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the command and status register of */ /* port 2 */ - /***************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Inhibits the pattern interrupt */ - /*************************************/ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************************/ /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */ - /*****************************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************/ /* Enable Port B */ - /*****************/ outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_Event2InterruptStatus = 0; } /* if(i_Event2Status==1) */ else { - printk("\nEvent 2 not initialised\n"); + dev_warn(dev->hw_dev, + "Event 2 not initialised\n"); return -EINVAL; } /* else if(i_Event2Status==1) */ } /* if(data[1]==2) */ } /* if (data[1] == 1 || data[1] == 2) */ else { - printk("\nThe port parameter is in error\n"); + dev_warn(dev->hw_dev, + "The port parameter is in error\n"); return -EINVAL; } /* else if (data[1] == 1 || data[1] == 2) */ break; default: - printk("\nThe option of START/STOP logic does not exist\n"); + dev_warn(dev->hw_dev, + "The option of START/STOP logic does not exist\n"); return -EINVAL; } /* switch(data[0]) */ @@ -769,33 +655,17 @@ static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_Initialisation | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the digital input | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_Initialisation(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Return the status of the digital input + */ +static int apci1500_di_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; int i_DummyRead = 0; - /******************/ + /* Software reset */ - /******************/ i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -803,16 +673,12 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the master configuration control register */ - /*****************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -844,9 +710,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -876,9 +740,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the data path polarity register of port C */ - /*****************************************************/ outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* High level of port C means 1 */ @@ -893,9 +755,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes it */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 1 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -905,9 +765,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates the interrupt management of timer 1 */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 2 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -917,9 +775,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates Timer 2 interrupt management: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 3 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -929,9 +785,7 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates interrupt management of timer 3: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ @@ -939,149 +793,46 @@ static int i_APCI1500_Initialisation(struct comedi_device *dev, return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadMoreDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the Requested digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To be Read | -| unsigned int *data : Data Pointer -| data[0] : 0 Read a single channel -| 1 read a port value -| data[1] : port value -+----------------------------------------------------------------------------+ -| Output Parameters : -- data[0] :The read status value -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadMoreDigitalInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci1500_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int ui_PortValue = data[1]; - unsigned int ui_Mask = 0; - unsigned int ui_Channel; - unsigned int ui_TmpValue = 0; - ui_Channel = CR_CHAN(insn->chanspec); + struct addi_private *devpriv = dev->private; - switch (data[0]) { - case 0: - if (ui_Channel <= 15) { - ui_TmpValue = - (unsigned int) inw(devpriv->i_IobaseAddon + - APCI1500_DIGITAL_IP); - *data = (ui_TmpValue >> ui_Channel) & 0x1; - } /* if(ui_Channel >= 0 && ui_Channel <=15) */ - else { - printk("\nThe channel specification are in error\n"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* else if(ui_Channel >= 0 && ui_Channel <=15) */ - break; - case 1: + data[1] = inw(devpriv->i_IobaseAddon + APCI1500_DIGITAL_IP); - *data = (unsigned int) inw(devpriv->i_IobaseAddon + - APCI1500_DIGITAL_IP); - switch (ui_Channel) { - case 2: - ui_Mask = 3; - *data = (*data >> (2 * ui_PortValue)) & ui_Mask; - break; - case 4: - ui_Mask = 15; - *data = (*data >> (4 * ui_PortValue)) & ui_Mask; - break; - case 8: - ui_Mask = 255; - *data = (*data >> (8 * ui_PortValue)) & ui_Mask; - break; - case 15: - break; - - default: - printk("\nSpecified channel cannot be read \n"); - return -EINVAL; /* "sorry channel spec wrong " */ - break; - } /* switch(ui_Channel) */ - break; - default: - printk("\nThe specified functionality does not exist\n"); - return -EINVAL; - } /* switch(data[0]) */ return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigDigitalOutputErrorInterrupt -| (struct comedi_device *dev,struct comedi_subdevice *s struct comedi_insn -| *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures the digital output memory and the digital -| output error interrupt | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| data[0] :1:Memory on | -| 0:Memory off | -| data[1] :1 Enable the voltage error interrupt -| :0 Disable the voltage error interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the digital output memory and the digital output error interrupt + * + * data[1] 1 = Enable the voltage error interrupt + * 2 = Disable the voltage error interrupt + */ +static int apci1500_do_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; + devpriv->b_OutputMemoryStatus = data[0]; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To Write | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Writes port value to the selected port + */ +static int apci1500_do_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - static unsigned int ui_Temp = 0; + struct addi_private *devpriv = dev->private; + static unsigned int ui_Temp; unsigned int ui_Temp1; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ if (!devpriv->b_OutputMemoryStatus) { @@ -1131,7 +882,9 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, APCI1500_DIGITAL_OP); } /* if(data[1]==1) */ else { - printk("\nSpecified channel not supported\n"); + dev_warn(dev->hw_dev, + "Specified channel not supported\n"); + return -EINVAL; } /* else if(data[1]==1) */ } /* elseif(data[1]==0) */ } /* if(data[3]==0) */ @@ -1208,12 +961,15 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, APCI1500_DIGITAL_OP); } /* if(data[1]==1) */ else { - printk("\nSpecified channel not supported\n"); + dev_warn(dev->hw_dev, + "Specified channel not supported\n"); + return -EINVAL; } /* else if(data[1]==1) */ } /* elseif(data[1]==0) */ } /* if(data[3]==1); */ else { - printk("\nSpecified functionality does not exist\n"); + dev_warn(dev->hw_dev, + "Specified functionality does not exist\n"); return -EINVAL; } /* if else data[3]==1) */ } /* if else data[3]==0) */ @@ -1222,58 +978,25 @@ static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigCounterTimerWatchdog(comedi_device -| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status data[0] : 2 APCI1500_1_8_KHZ -| 1 APCI1500_3_6_KHZ | -| 0 APCI1500_115_KHZ -| data[1] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| data[2] : 0 Counter -| 1 Timer/Watchdog -| data[3] : This parameter has | -| two meanings. | -| - If the counter/timer | -| is used as a counter | -| the limit value of | -| the counter is given | -| | -| - If the counter/timer | -| is used as a timer, | -| the divider factor | -| for the output is | -| given. -| data[4] : 0 APCI1500_CONTINUOUS -| 1 APCI1500_SINGLE -| data[5] : 0 Software Trigger -| 1 Hardware Trigger -| -| data[6] :0 Software gate -| 1 Hardware gate -| data[7] :0 Interrupt Disable -| 1 Interrupt Enable -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures The Watchdog + * + * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ + * data[1] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + * data[2] 0 = Counter, 1 = Timer/Watchdog + * data[3] This parameter has two meanings. If the counter/timer is used as + * a counter the limit value of the counter is given. If the counter/timer + * is used as a timer, the divider factor for the output is given. + * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE + * data[5] 0 = Software Trigger, 1 = Hardware Trigger + * data[6] 0 = Software gate, 1 = Hardware gate + * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable + */ +static int apci1500_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; int i_TimerCounterMode, i_MasterConfiguration; devpriv->tsk_Current = current; @@ -1284,7 +1007,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, } /* if(data[0]==0||data[0]==1||data[0]==2) */ else { if (data[0] != 3) { - printk("\nThe option for input clock selection does not exist\n"); + dev_warn(dev->hw_dev, + "The option for input clock selection does not exist\n"); return -EINVAL; } /* if(data[0]!=3) */ } /* elseif(data[0]==0||data[0]==1||data[0]==2) */ @@ -1300,7 +1024,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - printk("\nThis choice is not a timer nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a timer nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1313,139 +1038,110 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ i_TimerCounterMode = data[2] | data[4] | 7; - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of timer/counter 1 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 1 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 1 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables timer/counter 1 and triggers timer/counter 1 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x40; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 1 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Disable timer/counter 1 */ - /***************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 1 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Trigger timer/counter 1 */ - /***************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1461,7 +1157,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_TIMER; break; default: - printk("\nThis choice is not a timer nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a timer nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1474,7 +1171,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ @@ -1487,7 +1185,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[5] = APCI1500_HARDWARE_TRIGGER; break; default: - printk("\nThis choice for software or hardware trigger does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware trigger does not exist\n"); return -EINVAL; } /* switch(data[5]) */ @@ -1500,140 +1199,111 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - printk("\nThis choice for software or hardware gate does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware gate does not exist\n"); return -EINVAL; } /* switch(data[6]) */ i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7; - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of timer/counter 2 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 2 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of timer/counter 2 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables timer/counter 2 and triggers timer/counter 2 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x20; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 2 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Disable timer/counter 2 */ - /***************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************/ /* Selects the commands register of */ /* timer/counter 2 */ - /****************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Trigger timer/counter 1 */ - /***************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1649,7 +1319,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[2] = APCI1500_WATCHDOG; break; default: - printk("\nThis choice is not a watchdog nor a counter\n"); + dev_warn(dev->hw_dev, + "This choice is not a watchdog nor a counter\n"); return -EINVAL; } /* switch(data[2]) */ @@ -1662,7 +1333,8 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[4] = APCI1500_SINGLE; break; default: - printk("\nThis option for single/continuous mode does not exist\n"); + dev_warn(dev->hw_dev, + "This option for single/continuous mode does not exist\n"); return -EINVAL; } /* switch(data[4]) */ @@ -1675,146 +1347,109 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, data[6] = APCI1500_HARDWARE_GATE; break; default: - printk("\nThis choice for software or hardware gate does not exist\n"); + dev_warn(dev->hw_dev, + "This choice for software or hardware gate does not exist\n"); return -EINVAL; } /* switch(data[6]) */ - /*****************************/ /* Test if used for watchdog */ - /*****************************/ if (data[2] == APCI1500_WATCHDOG) { - /*****************************/ /* - Enables the output line */ /* - Enables retrigger */ /* - Pulses output */ - /*****************************/ i_TimerCounterMode = data[2] | data[4] | 0x54; } /* if (data[2] == APCI1500_WATCHDOG) */ else { i_TimerCounterMode = data[2] | data[4] | data[6] | 7; } /* elseif (data[2] == APCI1500_WATCHDOG) */ - /*************************/ /* Test the reload value */ - /*************************/ if ((data[3] >= 0) && (data[3] <= 65535)) { if (data[7] == APCI1500_ENABLE || data[7] == APCI1500_DISABLE) { - /************************************************/ /* Selects the mode register of watchdog/counter 3 */ - /************************************************/ outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************/ /* Writes the new mode */ - /***********************/ outb(i_TimerCounterMode, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of watchdog/counter 3 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************/ /* Writes the low value */ - /*************************/ outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /****************************************************/ /* Selects the constant register of watchdog/counter 3 */ - /****************************************************/ outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**************************/ /* Writes the high value */ - /**************************/ data[3] = data[3] >> 8; outb(data[3], devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************/ /* Reads the register */ - /**********************/ i_MasterConfiguration = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************************************/ /* Enables watchdog/counter 3 and triggers watchdog/counter 3 */ - /********************************************************/ i_MasterConfiguration = i_MasterConfiguration | 0x10; - /*********************************************/ /* Selects the master configuration register */ - /*********************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************************/ /* Writes the new configuration */ - /********************************/ outb(i_MasterConfiguration, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /********************/ /* Test if COUNTER */ - /********************/ if (data[2] == APCI1500_COUNTER) { - /*************************************/ /* Selects the command register of */ /* watchdog/counter 3 */ - /*************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Disable the watchdog/counter 3 and starts it */ - /*************************************************/ outb(0x0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************/ /* Selects the command register of */ /* watchdog/counter 3 */ - /*************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Trigger the watchdog/counter 3 and starts it */ - /*************************************************/ outb(0x2, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1823,12 +1458,14 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, } /* if(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ else { - printk("\nError in selection of interrupt enable or disable\n"); + dev_warn(dev->hw_dev, + "Error in selection of interrupt enable or disable\n"); return -EINVAL; } /* elseif(data[7]== APCI1500_ENABLE ||data[7]== APCI1500_DISABLE) */ } /* if ((data[3]>= 0) && (data[3] <= 65535)) */ else { - printk("\nError in selection of reload value\n"); + dev_warn(dev->hw_dev, + "Error in selection of reload value\n"); return -EINVAL; } /* else if ((data[3]>= 0) && (data[3] <= 65535)) */ i_TimerCounterWatchdogInterrupt = data[7]; @@ -1836,45 +1473,27 @@ static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, break; default: - printk("\nThe specified counter\timer option does not exist\n"); + dev_warn(dev->hw_dev, + "The specified counter/timer option does not exist\n"); + return -EINVAL; } /* switch(data[1]) */ i_CounterLogic = data[2]; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_StartStopTriggerTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, -| struct comedi_insn *insn,unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Start / Stop or trigger the timer counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -| data[0] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| data[1] : 0 start -| 1 stop -| 2 Trigger -| data[2] : 0 Counter -| 1 Timer/Watchdog -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Start / Stop or trigger the timer counter or Watchdog + * + * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + * data[1] 0 = Start, 1 = Stop, 2 = Trigger + * data[2] 0 = Counter, 1 = Timer/Watchdog + */ +static int apci1500_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; int i_CommandAndStatusValue; switch (data[0]) { @@ -1888,13 +1507,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts timer/counter 1 */ - /**************************/ i_TimerCounter1Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1903,20 +1518,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nCounter/Timer1 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer1 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop timer/counter 1 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1929,23 +1541,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case TRIGGER: if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_TimerCounter1Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_TimerCounter1Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1954,13 +1560,15 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nCounter/Timer1 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer1 not configured\n"); return -EINVAL; } break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; @@ -1975,13 +1583,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts timer/counter 2 */ - /**************************/ i_TimerCounter2Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -1990,20 +1594,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nCounter/Timer2 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer2 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop timer/counter 2 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2015,23 +1616,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case TRIGGER: if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_TimerCounter2Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_TimerCounter2Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2040,12 +1635,14 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nCounter/Timer2 not configured\n"); + dev_warn(dev->hw_dev, + "Counter/Timer2 not configured\n"); return -EINVAL; } break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; @@ -2060,13 +1657,9 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device else { i_CommandAndStatusValue = 0xE4; /* disable the interrupt */ } /* elseif(i_TimerCounterWatchdogInterrupt==1) */ - /**************************/ /* Starts Watchdog/counter 3 */ - /**************************/ i_WatchdogCounter3Enabled = 1; - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2076,20 +1669,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device } /* if( i_WatchdogCounter3init==1) */ else { - printk("\nWatchdog/Counter3 not configured\n"); + dev_warn(dev->hw_dev, + "Watchdog/Counter3 not configured\n"); return -EINVAL; } break; case STOP: - /**************************/ /* Stop Watchdog/counter 3 */ - /**************************/ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2104,23 +1694,17 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device case 0: /* triggering counter 3 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { - /************************/ /* Set Trigger and gate */ - /************************/ i_CommandAndStatusValue = 0x6; } /* if( i_WatchdogCounter3Enabled==1) */ else { - /***************/ /* Set Trigger */ - /***************/ i_CommandAndStatusValue = 0x2; } /* elseif(i_WatchdogCounter3Enabled==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2129,7 +1713,8 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nCounter3 not configured\n"); + dev_warn(dev->hw_dev, + "Counter3 not configured\n"); return -EINVAL; } break; @@ -2137,9 +1722,7 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device /* triggering Watchdog 3 */ if (i_WatchdogCounter3Init == 1) { - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2148,79 +1731,60 @@ static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nWatchdog 3 not configured\n"); + dev_warn(dev->hw_dev, + "Watchdog 3 not configured\n"); return -EINVAL; } break; default: - printk("\nWrong choice of watchdog/counter3\n"); + dev_warn(dev->hw_dev, + "Wrong choice of watchdog/counter3\n"); return -EINVAL; } /* switch(data[2]) */ break; default: - printk("\nThe specified option for start/stop/trigger does not exist\n"); + dev_warn(dev->hw_dev, + "The specified option for start/stop/trigger does not exist\n"); return -EINVAL; } /* switch(data[1]) */ break; default: - printk("\nThe specified choice for counter/watchdog/timer does not exist\n"); + dev_warn(dev->hw_dev, + "The specified choice for counter/watchdog/timer does not exist\n"); return -EINVAL; } /* switch(data[0]) */ return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadCounterTimerWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -| data[0] : 0 Counter1/Timer1 -| 1 Counter2/Timer2 -| 2 Counter3/Watchdog -| -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read The Watchdog + * + * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog + */ +static int apci1500_timer_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; int i_CommandAndStatusValue; + switch (data[0]) { case COUNTER1: /* Read counter/timer1 */ if (i_TimerCounter1Init == 1) { if (i_TimerCounter1Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter1Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_TimerCounter1Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2228,9 +1792,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR1_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2247,7 +1809,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter1Init==1) */ else { - printk("\nTimer/Counter1 not configured\n"); + dev_warn(dev->hw_dev, + "Timer/Counter1 not configured\n"); return -EINVAL; } /* elseif( i_TimerCounter1Init==1) */ break; @@ -2255,23 +1818,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/timer2 */ if (i_TimerCounter2Init == 1) { if (i_TimerCounter2Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter2Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_TimerCounter2Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2279,9 +1836,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR2_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2298,7 +1853,8 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_TimerCounter2Init==1) */ else { - printk("\nTimer/Counter2 not configured\n"); + dev_warn(dev->hw_dev, + "Timer/Counter2 not configured\n"); return -EINVAL; } /* elseif( i_TimerCounter2Init==1) */ break; @@ -2306,23 +1862,17 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, /* Read counter/watchdog2 */ if (i_WatchdogCounter3Init == 1) { if (i_WatchdogCounter3Enabled == 1) { - /************************/ /* Set RCC and gate */ - /************************/ i_CommandAndStatusValue = 0xC; } /* if( i_TimerCounter2Init==1) */ else { - /***************/ /* Set RCC */ - /***************/ i_CommandAndStatusValue = 0x8; } /* elseif(i_WatchdogCounter3Init==1) */ - /********************************************/ /* Selects the commands and status register */ - /********************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2330,9 +1880,7 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************/ /* Selects the counter register (high) */ - /***************************************/ outb(APCI1500_R_CPT_TMR3_VALUE_HIGH, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2349,12 +1897,14 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, APCI1500_Z8536_CONTROL_REGISTER); } /* if( i_WatchdogCounter3Init==1) */ else { - printk("\nWatchdogCounter3 not configured\n"); + dev_warn(dev->hw_dev, + "WatchdogCounter3 not configured\n"); return -EINVAL; } /* elseif( i_WatchdogCounter3Init==1) */ break; default: - printk("\nThe choice of timer/counter/watchdog does not exist\n"); + dev_warn(dev->hw_dev, + "The choice of timer/counter/watchdog does not exist\n"); return -EINVAL; } /* switch(data[0]) */ @@ -2362,31 +1912,15 @@ static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ReadInterruptMask | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read the interrupt mask | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | - - -+----------------------------------------------------------------------------+ -| Output Parameters : -- data[0]:The interrupt mask value data[1]:Channel no -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Read the interrupt mask + * + * data[0] The interrupt mask value + * data[1] Channel Number + */ +static int apci1500_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { data[0] = i_InterruptMask; data[1] = i_InputChannel; @@ -2395,35 +1929,18 @@ static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_ConfigureInterrupt | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Configures the interrupt registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer | -| - -+----------------------------------------------------------------------------+ -| Output Parameters : -- -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) + * Configures the interrupt registers + */ +static int apci1500_do_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_Status; int i_RegValue; int i_Constant; + devpriv->tsk_Current = current; outl(0x0, devpriv->i_IobaseAmcc + 0x38); if (data[0] == 1) { @@ -2434,140 +1951,101 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, i_Constant = 0x00; } /* if{data[0]==0) */ else { - printk("\nThe parameter passed to driver is in error for enabling the voltage interrupt\n"); + dev_warn(dev->hw_dev, + "The parameter passed to driver is in error for enabling the voltage interrupt\n"); return -EINVAL; } /* else if(data[0]==0) */ } /* elseif(data[0]==1) */ - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*********************************************/ /* Writes the new configuration (APCI1500_OR) */ - /*********************************************/ i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************/ /* Authorises the interrupt on the board */ - /*****************************************/ outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the pattern polarity register of port B */ - /***************************************************/ outb(APCI1500_RW_PORT_B_PATTERN_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the pattern transition register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************************/ /* Selects the pattern mask register of port B */ - /***********************************************/ outb(APCI1500_RW_PORT_B_PATTERN_MASK, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port A */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port B */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 1 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 2 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 3 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************/ /* Enables the PCI interrupt */ - /*****************************/ outl(0x3000, devpriv->i_IobaseAmcc + 0x38); ui_Status = inl(devpriv->i_IobaseAmcc + 0x10); ui_Status = inl(devpriv->i_IobaseAmcc + 0x38); @@ -2576,69 +2054,37 @@ static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, return insn->n; } -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1500_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1500_Interrupt(int irq, void *d) +static void apci1500_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct addi_private *devpriv = dev->private; unsigned int ui_InterruptStatus = 0; int i_RegValue = 0; i_InterruptMask = 0; - /***********************************/ /* Read the board interrupt status */ - /***********************************/ ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38); - /***************************************/ /* Test if board generated a interrupt */ - /***************************************/ if ((ui_InterruptStatus & 0x800000) == 0x800000) { - /************************/ /* Disable all Interrupt */ - /************************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ /* outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /**********************************************/ /* Disables the main interrupt on the board */ - /**********************************************/ /* outb(0x00,devpriv->iobase+APCI1500_Z8536_CONTROL_REGISTER); */ - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port A */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2652,9 +2098,7 @@ static void v_APCI1500_Interrupt(int irq, void *d) inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***************************************************/ /* Selects the interrupt vector register of port A */ - /***************************************************/ outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2670,45 +2114,32 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* elseif(i_Logic==APCI1500_OR_PRIORITY) */ } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of port B */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - printk("\n\n\n"); - /****************/ /* Reads port B */ - /****************/ i_RegValue = inb((unsigned int) devpriv->iobase + APCI1500_Z8536_PORT_B); i_RegValue = i_RegValue & 0xC0; - /**************************************/ /* Tests if this is an external error */ - /**************************************/ if (i_RegValue) { /* Disable the interrupt */ - /*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outl(0x0, devpriv->i_IobaseAmcc + 0x38); if (i_RegValue & 0x80) { @@ -2726,46 +2157,34 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* if (i_RegValue) */ } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 1 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_InterruptMask = i_InterruptMask | 4; } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 2 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2773,23 +2192,17 @@ static void v_APCI1500_Interrupt(int irq, void *d) i_InterruptMask = i_InterruptMask | 8; } /* if ((i_RegValue & 0x60) == 0x60) */ - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); if ((i_RegValue & 0x60) == 0x60) { - /*****************************************************/ /* Selects the command and status register of timer 3 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /***********************************/ /* Deletes the interrupt of timer 3 */ - /***********************************/ i_RegValue = (i_RegValue & 0x0F) | 0x20; outb(i_RegValue, devpriv->iobase + @@ -2803,44 +2216,27 @@ static void v_APCI1500_Interrupt(int irq, void *d) } /* if ((i_RegValue & 0x60) == 0x60) */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - /***********************/ /* Enable all Interrupts */ - /***********************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /**********************************************/ /* Authorizes the main interrupt on the board */ - /**********************************************/ outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); } /* if ((ui_InterruptStatus & 0x800000) == 0x800000) */ else { - printk("\nInterrupt from unknown source\n"); + dev_warn(dev->hw_dev, + "Interrupt from unknown source\n"); } /* else if ((ui_InterruptStatus & 0x800000) == 0x800000) */ return; } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1500_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI1500_Reset(struct comedi_device *dev) +static int apci1500_reset(struct comedi_device *dev) { + struct addi_private *devpriv = dev->private; int i_DummyRead = 0; + i_TimerCounter1Init = 0; i_TimerCounter2Init = 0; i_WatchdogCounter3Init = 0; @@ -2855,9 +2251,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) i_TimerCounter2Enabled = 0; i_WatchdogCounter3Enabled = 0; - /******************/ /* Software reset */ - /******************/ i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2865,16 +2259,12 @@ static int i_APCI1500_Reset(struct comedi_device *dev) outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the master configuration control register */ - /*****************************************************/ outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2906,9 +2296,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the mode specification register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_SPECIFICATION, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); @@ -2938,9 +2326,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) /* Deletes the register */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the data path polarity register of port C */ - /*****************************************************/ outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* High level of port C means 1 */ @@ -2955,9 +2341,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes it */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 1 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -2967,9 +2351,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates the interrupt management of timer 1 */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 2 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -2979,9 +2361,7 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates Timer 2 interrupt management: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /******************************************************/ /* Selects the command and status register of timer 3 */ - /******************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes IP and IUS */ @@ -2991,71 +2371,43 @@ static int i_APCI1500_Reset(struct comedi_device *dev) devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deactivates interrupt management of timer 3: */ outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* Deletes all interrupts */ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); /* reset all the digital outputs */ outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP); -/*******************************/ /* Disable the board interrupt */ -/*******************************/ - /*************************************************/ /* Selects the master interrupt control register */ - /*************************************************/ outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); - /*****************************************************/ /* Selects the command and status register of port A */ - /*****************************************************/ outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of port B */ - /*****************************************************/ outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 1 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR1_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 2 */ - /*****************************************************/ outb(APCI1500_RW_CPT_TMR2_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/*****************************************************/ /* Selects the command and status register of timer 3*/ -/*****************************************************/ outb(APCI1500_RW_CPT_TMR3_CMD_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); -/****************************/ /* Deactivates all interrupts */ -/******************************/ outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER); return 0; } diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h deleted file mode 100644 index 647f9ebf552..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * 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. - */ - -/********* Definitions for APCI-1500 card *****/ - -/* Card Specific information */ -#define APCI1500_BOARD_VENDOR_ID 0x10e8 -#define APCI1500_ADDRESS_RANGE 4 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI1500_DIGITAL_OP 2 -#define APCI1500_DIGITAL_IP 0 -#define APCI1500_AND 2 -#define APCI1500_OR 4 -#define APCI1500_OR_PRIORITY 6 -#define APCI1500_CLK_SELECT 0 -#define COUNTER1 0 -#define COUNTER2 1 -#define COUNTER3 2 -#define APCI1500_COUNTER 0x20 -#define APCI1500_TIMER 0 -#define APCI1500_WATCHDOG 0 -#define APCI1500_SINGLE 0 -#define APCI1500_CONTINUOUS 0x80 -#define APCI1500_DISABLE 0 -#define APCI1500_ENABLE 1 -#define APCI1500_SOFTWARE_TRIGGER 0x4 -#define APCI1500_HARDWARE_TRIGGER 0x10 -#define APCI1500_SOFTWARE_GATE 0 -#define APCI1500_HARDWARE_GATE 0x8 -#define START 0 -#define STOP 1 -#define TRIGGER 2 - -/* - * Zillog I/O enumeration - */ -enum { - APCI1500_Z8536_PORT_C, - APCI1500_Z8536_PORT_B, - APCI1500_Z8536_PORT_A, - APCI1500_Z8536_CONTROL_REGISTER -}; - -/* - * Z8536 CIO Internal Address - */ -enum { - APCI1500_RW_MASTER_INTERRUPT_CONTROL, - APCI1500_RW_MASTER_CONFIGURATION_CONTROL, - APCI1500_RW_PORT_A_INTERRUPT_CONTROL, - APCI1500_RW_PORT_B_INTERRUPT_CONTROL, - APCI1500_RW_TIMER_COUNTER_INTERRUPT_VECTOR, - APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY, - APCI1500_RW_PORT_C_DATA_DIRECTION, - APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL, - - APCI1500_RW_PORT_A_COMMAND_AND_STATUS, - APCI1500_RW_PORT_B_COMMAND_AND_STATUS, - APCI1500_RW_CPT_TMR1_CMD_STATUS, - APCI1500_RW_CPT_TMR2_CMD_STATUS, - APCI1500_RW_CPT_TMR3_CMD_STATUS, - APCI1500_RW_PORT_A_DATA, - APCI1500_RW_PORT_B_DATA, - APCI1500_RW_PORT_C_DATA, - - APCI1500_R_CPT_TMR1_VALUE_HIGH, - APCI1500_R_CPT_TMR1_VALUE_LOW, - APCI1500_R_CPT_TMR2_VALUE_HIGH, - APCI1500_R_CPT_TMR2_VALUE_LOW, - APCI1500_R_CPT_TMR3_VALUE_HIGH, - APCI1500_R_CPT_TMR3_VALUE_LOW, - APCI1500_RW_CPT_TMR1_TIME_CST_HIGH, - APCI1500_RW_CPT_TMR1_TIME_CST_LOW, - APCI1500_RW_CPT_TMR2_TIME_CST_HIGH, - APCI1500_RW_CPT_TMR2_TIME_CST_LOW, - APCI1500_RW_CPT_TMR3_TIME_CST_HIGH, - APCI1500_RW_CPT_TMR3_TIME_CST_LOW, - APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION, - APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION, - APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION, - APCI1500_R_CURRENT_VECTOR, - - APCI1500_RW_PORT_A_SPECIFICATION, - APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION, - APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY, - APCI1500_RW_PORT_A_DATA_DIRECTION, - APCI1500_RW_PORT_A_SPECIAL_IO_CONTROL, - APCI1500_RW_PORT_A_PATTERN_POLARITY, - APCI1500_RW_PORT_A_PATTERN_TRANSITION, - APCI1500_RW_PORT_A_PATTERN_MASK, - - APCI1500_RW_PORT_B_SPECIFICATION, - APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION, - APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY, - APCI1500_RW_PORT_B_DATA_DIRECTION, - APCI1500_RW_PORT_B_SPECIAL_IO_CONTROL, - APCI1500_RW_PORT_B_PATTERN_POLARITY, - APCI1500_RW_PORT_B_PATTERN_TRANSITION, - APCI1500_RW_PORT_B_PATTERN_MASK -}; - - /*----------DIGITAL INPUT----------------*/ -static int i_APCI1500_Initialisation(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int i_APCI1500_ConfigDigitalInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int i_APCI1500_StartStopInputEvent(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int i_APCI1500_ReadMoreDigitalInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/*---------- DIGITAL OUTPUT------------*/ -static int i_APCI1500_ConfigDigitalOutputErrorInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int i_APCI1500_WriteDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/*----------TIMER----------------*/ -static int i_APCI1500_ConfigCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int i_APCI1500_StartStopTriggerTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int i_APCI1500_ReadCounterTimerWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int i_APCI1500_ReadInterruptMask(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/*----------INTERRUPT HANDLER------*/ -static void v_APCI1500_Interrupt(int irq, void *d); -static int i_APCI1500_ConfigureInterrupt(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -/*----------RESET---------------*/ -static int i_APCI1500_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c deleted file mode 100644 index 8a584a014b0..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.c +++ /dev/null @@ -1,542 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1516 | Compiler : GCC | - | Module name : hwdrv_apci1516.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1516 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ -#include "hwdrv_apci1516.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1516_Read1DigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the digital input | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1516_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_TmpValue = 0; - unsigned int ui_Channel; - ui_Channel = CR_CHAN(insn->chanspec); - if (ui_Channel <= 7) { - ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI1516_DIGITAL_IP); - /* since only 1 channel reqd to bring it to last bit it is rotated */ - /* 8 +(chan - 1) times then ANDed with 1 for last bit. */ - *data = (ui_TmpValue >> ui_Channel) & 0x1; - } /* if(ui_Channel >= 0 && ui_Channel <=7) */ - else { - /* comedi_error(dev," \n chan spec wrong\n"); */ - return -EINVAL; /* "sorry channel spec wrong " */ - } /* else if(ui_Channel >= 0 && ui_Channel <=7) */ - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1516_ReadMoreDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the Requested digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1516_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - unsigned int ui_PortValue = data[0]; - unsigned int ui_Mask = 0; - unsigned int ui_NoOfChannels; - - ui_NoOfChannels = CR_CHAN(insn->chanspec); - - *data = (unsigned int) inw(devpriv->iobase + APCI1516_DIGITAL_IP); - switch (ui_NoOfChannels) { - case 2: - ui_Mask = 3; - *data = (*data >> (2 * ui_PortValue)) & ui_Mask; - break; - case 4: - ui_Mask = 15; - *data = (*data >> (4 * ui_PortValue)) & ui_Mask; - break; - case 7: - break; - - default: - printk("\nWrong parameters\n"); - return -EINVAL; /* "sorry channel spec wrong " */ - break; - } /* switch(ui_NoOfChannels) */ - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1516_ConfigDigitalOutput (struct comedi_device *dev, -| struct comedi_subdevice *s struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| data[0] :1:Memory on | -| 0:Memory off | -| | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1516_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - devpriv->b_OutputMemoryStatus = data[0]; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1516_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1516_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp, ui_Temp1; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - - printk("EL311003 : @=%x\n", devpriv->iobase + APCI1516_DIGITAL_OP); - - if (devpriv->b_OutputMemoryStatus) { - ui_Temp = inw(devpriv->iobase + APCI1516_DIGITAL_OP); - - } /* if(devpriv->b_OutputMemoryStatus ) */ - else { - 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->iobase + APCI1516_DIGITAL_OP); - - printk("EL311003 : d=%d @=%x\n", data[0], - devpriv->iobase + APCI1516_DIGITAL_OP); - - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = - (data[0] << (2 * - data[2])) | ui_Temp; - break; - - case 4: - data[0] = - (data[0] << (4 * - data[2])) | ui_Temp; - break; - - case 7: - data[0] = data[0] | ui_Temp; - break; - - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - - outw(data[0], - devpriv->iobase + APCI1516_DIGITAL_OP); - - printk("EL311003 : d=%d @=%x\n", data[0], - devpriv->iobase + APCI1516_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==0) */ - else { - if (data[3] == 1) { - if (data[1] == 0) { - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = (data[0] << ui_NoOfChannel) ^ 0xff; - data[0] = data[0] & ui_Temp; - outw(data[0], - devpriv->iobase + APCI1516_DIGITAL_OP); - - printk("EL311003 : d=%d @=%x\n", data[0], - devpriv->iobase + APCI1516_DIGITAL_OP); - - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = ~data[0] & 0x3; - ui_Temp1 = 3; - ui_Temp1 = - ui_Temp1 << 2 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (2 * - data - [2])) ^ - 0xff) & ui_Temp; - break; - - case 4: - data[0] = ~data[0] & 0xf; - ui_Temp1 = 15; - ui_Temp1 = - ui_Temp1 << 4 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (4 * - data - [2])) ^ - 0xff) & ui_Temp; - break; - - case 7: - break; - - default: - comedi_error(dev, - " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - - outw(data[0], - devpriv->iobase + - APCI1516_DIGITAL_OP); - - printk("EL311003 : d=%d @=%x\n", - data[0], - devpriv->iobase + - APCI1516_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==1); */ - else { - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* if else data[3]==1) */ - } /* if else data[3]==0) */ - return (insn->n); -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1516_ReadDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel or port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1516_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - unsigned int ui_Temp; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - ui_Temp = data[0]; - *data = inw(devpriv->iobase + APCI1516_DIGITAL_OP_RW); - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if(ui_Temp==0) */ - else { - if (ui_Temp == 1) { - switch (ui_NoOfChannel) { - - case 2: - *data = (*data >> (2 * data[1])) & 3; - break; - - case 4: - *data = (*data >> (4 * data[1])) & 15; - break; - - case 7: - break; - - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - } /* if(ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* elseif(ui_Temp==1) */ - } /* elseif(ui_Temp==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1516_ConfigWatchdog(struct comedi_device *dev, -| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1516_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (data[0] == 0) { - /* Disable the watchdog */ - outw(0x0, - devpriv->i_IobaseAddon + - APCI1516_WATCHDOG_ENABLEDISABLE); - /* Loading the Reload value */ - outw(data[1], - devpriv->i_IobaseAddon + - APCI1516_WATCHDOG_RELOAD_VALUE); - data[1] = data[1] >> 16; - outw(data[1], - devpriv->i_IobaseAddon + - APCI1516_WATCHDOG_RELOAD_VALUE + 2); - } /* if(data[0]==0) */ - else { - printk("\nThe input parameters are wrong\n"); - return -EINVAL; - } /* elseif(data[0]==0) */ - - return insn->n; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI1516_StartStopWriteWatchdog | - | (struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data); | - +----------------------------------------------------------------------------+ - | Task : Start / Stop The Watchdog | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ - */ - -int i_APCI1516_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - switch (data[0]) { - case 0: /* stop the watchdog */ - outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE); /* disable the watchdog */ - break; - case 1: /* start the watchdog */ - outw(0x0001, - devpriv->i_IobaseAddon + - APCI1516_WATCHDOG_ENABLEDISABLE); - break; - case 2: /* Software trigger */ - outw(0x0201, - devpriv->i_IobaseAddon + - APCI1516_WATCHDOG_ENABLEDISABLE); - break; - default: - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* switch(data[0]) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1516_ReadWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, - unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1516_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[0] = inw(devpriv->i_IobaseAddon + APCI1516_WATCHDOG_STATUS) & 0x1; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1516_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1516_Reset(struct comedi_device *dev) -{ - outw(0x0, devpriv->iobase + APCI1516_DIGITAL_OP); /* RESETS THE DIGITAL OUTPUTS */ - outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_ENABLEDISABLE); - outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_RELOAD_VALUE); - outw(0x0, devpriv->i_IobaseAddon + APCI1516_WATCHDOG_RELOAD_VALUE + 2); - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h deleted file mode 100644 index 44728293e49..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1516.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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. - */ - -/********* Definitions for APCI-1516 card *****/ - -/* Card Specific information */ -#define APCI1516_BOARD_VENDOR_ID 0x15B8 -#define APCI1516_ADDRESS_RANGE 8 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI1516_DIGITAL_OP 4 -#define APCI1516_DIGITAL_OP_RW 4 -#define APCI1516_DIGITAL_IP 0 - -/* TIMER COUNTER WATCHDOG DEFINES */ - -#define ADDIDATA_WATCHDOG 2 -#define APCI1516_DIGITAL_OP_WATCHDOG 0 -#define APCI1516_WATCHDOG_ENABLEDISABLE 12 -#define APCI1516_WATCHDOG_RELOAD_VALUE 4 -#define APCI1516_WATCHDOG_STATUS 16 - -/* Hardware Layer functions for Apci1516 */ - -/* Digital Input */ -int i_APCI1516_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1516_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* Digital Output */ -int i_APCI1516_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1516_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1516_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* -* TIMER timer value is passed as u seconds -*/ -int i_APCI1516_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1516_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1516_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* reset */ -int i_APCI1516_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c index 5b92e45c9ae..0ba5385226a 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.c @@ -1,663 +1,252 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ /* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-1564 | Compiler : GCC | - | Module name : hwdrv_apci1564.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-1564 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * + * ADDI-DATA GmbH + * Dieselstrasse 3 + * D-77833 Ottersweier + * Tel: +19(0)7223/9493-0 + * Fax: +49(0)7223/9493-92 + * http://www.addi-data.com + * info@addi-data.com + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + */ + +#include "../addi_watchdog.h" + +#define APCI1564_ADDRESS_RANGE 128 + +/* Digital Input IRQ Function Selection */ +#define ADDIDATA_OR 0 +#define ADDIDATA_AND 1 + +/* Digital Input Interrupt Enable Disable. */ +#define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE 0x4 +#define APCI1564_DIGITAL_IP_INTERRUPT_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 + +/* TIMER COUNTER WATCHDOG DEFINES */ +#define ADDIDATA_TIMER 0 +#define ADDIDATA_COUNTER 1 +#define ADDIDATA_WATCHDOG 2 +#define APCI1564_COUNTER1 0 +#define APCI1564_COUNTER2 1 +#define APCI1564_COUNTER3 2 +#define APCI1564_COUNTER4 3 /* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ + * devpriv->i_IobaseAmcc Register Map + */ +#define APCI1564_DI_REG 0x04 +#define APCI1564_DI_INT_MODE1_REG 0x08 +#define APCI1564_DI_INT_MODE2_REG 0x0c +#define APCI1564_DI_INT_STATUS_REG 0x10 +#define APCI1564_DI_IRQ_REG 0x14 +#define APCI1564_DO_REG 0x18 +#define APCI1564_DO_INT_CTRL_REG 0x1c +#define APCI1564_DO_INT_STATUS_REG 0x20 +#define APCI1564_DO_IRQ_REG 0x24 +#define APCI1564_WDOG_REG 0x28 +#define APCI1564_WDOG_RELOAD_REG 0x2c +#define APCI1564_WDOG_TIMEBASE_REG 0x30 +#define APCI1564_WDOG_CTRL_REG 0x34 +#define APCI1564_WDOG_STATUS_REG 0x38 +#define APCI1564_WDOG_IRQ_REG 0x3c +#define APCI1564_WDOG_WARN_TIMEVAL_REG 0x40 +#define APCI1564_WDOG_WARN_TIMEBASE_REG 0x44 +#define APCI1564_TIMER_REG 0x48 +#define APCI1564_TIMER_RELOAD_REG 0x4c +#define APCI1564_TIMER_TIMEBASE_REG 0x50 +#define APCI1564_TIMER_CTRL_REG 0x54 +#define APCI1564_TIMER_STATUS_REG 0x58 +#define APCI1564_TIMER_IRQ_REG 0x5c +#define APCI1564_TIMER_WARN_TIMEVAL_REG 0x60 +#define APCI1564_TIMER_WARN_TIMEBASE_REG 0x64 -#include <linux/delay.h> -#include "hwdrv_apci1564.h" +/* + * dev>iobase Register Map + */ +#define APCI1564_TCW_REG(x) (0x00 + ((x) * 0x20)) +#define APCI1564_TCW_RELOAD_REG(x) (0x04 + ((x) * 0x20)) +#define APCI1564_TCW_TIMEBASE_REG(x) (0x08 + ((x) * 0x20)) +#define APCI1564_TCW_CTRL_REG(x) (0x0c + ((x) * 0x20)) +#define APCI1564_TCW_STATUS_REG(x) (0x10 + ((x) * 0x20)) +#define APCI1564_TCW_IRQ_REG(x) (0x14 + ((x) * 0x20)) +#define APCI1564_TCW_WARN_TIMEVAL_REG(x) (0x18 + ((x) * 0x20)) +#define APCI1564_TCW_WARN_TIMEBASE_REG(x) (0x1c + ((x) * 0x20)) /* Global variables */ -static unsigned int ui_InterruptStatus_1564 = 0; +static unsigned int ui_InterruptStatus_1564; static unsigned int ui_InterruptData, ui_Type; /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures the digital input Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 1 Enable Digital Input Interrupt | -| 0 Disable Digital Input Interrupt | -| data[1] : 0 ADDIDATA Interrupt OR LOGIC | -| : 1 ADDIDATA Interrupt AND LOGIC | -| data[2] : Interrupt mask for the mode 1 | -| data[3] : Interrupt mask for the mode 2 | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * Configures the digital input Subdevice + * + * data[0] 1 = Enable interrupt, 0 = Disable interrupt + * data[1] 0 = ADDIDATA Interrupt OR LOGIC, 1 = ADDIDATA Interrupt AND LOGIC + * data[2] Interrupt mask for the mode 1 + * data[3] Interrupt mask for the mode 2 + */ +static int apci1564_di_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; + devpriv->tsk_Current = current; - /*******************************/ + /* Set the digital input logic */ - /*******************************/ if (data[0] == ADDIDATA_ENABLE) { data[2] = data[2] << 4; data[3] = data[3] << 4; - outl(data[2], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE1); - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - if (data[1] == ADDIDATA_OR) { - outl(0x4, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* if (data[1] == ADDIDATA_OR) */ - else { - outl(0x6, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* else if (data[1] == ADDIDATA_OR) */ - } /* if (data[0] == ADDIDATA_ENABLE) */ - else { - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE1); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - } /* else if (data[0] == ADDIDATA_ENABLE) */ - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_Read1DigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the digital input | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_Channel : Channel number to read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_TmpValue = 0; - unsigned int ui_Channel; - - ui_Channel = CR_CHAN(insn->chanspec); - if (ui_Channel <= 31) { - ui_TmpValue = - (unsigned int) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); -/* -* since only 1 channel reqd to bring it to last bit it is rotated 8 -* +(chan - 1) times then ANDed with 1 for last bit. -*/ - *data = (ui_TmpValue >> ui_Channel) & 0x1; - } /* if (ui_Channel >= 0 && ui_Channel <=31) */ - else { - comedi_error(dev, "Not a valid channel number !!! \n"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* else if (ui_Channel >= 0 && ui_Channel <=31) */ - return insn->n; -} + outl(data[2], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + if (data[1] == ADDIDATA_OR) + outl(0x4, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + else + outl(0x6, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + } else { + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + } -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadMoreDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the Requested digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To be Read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_PortValue = data[0]; - unsigned int ui_Mask = 0; - unsigned int ui_NoOfChannels; - - ui_NoOfChannels = CR_CHAN(insn->chanspec); - if (data[1] == 0) { - *data = (unsigned int) inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP); - switch (ui_NoOfChannels) { - case 2: - ui_Mask = 3; - *data = (*data >> (2 * ui_PortValue)) & ui_Mask; - break; - case 4: - ui_Mask = 15; - *data = (*data >> (4 * ui_PortValue)) & ui_Mask; - break; - case 8: - ui_Mask = 255; - *data = (*data >> (8 * ui_PortValue)) & ui_Mask; - break; - case 16: - ui_Mask = 65535; - *data = (*data >> (16 * ui_PortValue)) & ui_Mask; - break; - case 31: - break; - default: - comedi_error(dev, "Not a valid Channel number !!!\n"); - return -EINVAL; /* "sorry channel spec wrong " */ - break; - } /* switch (ui_NoOfChannels) */ - } /* if (data[1]==0) */ - else { - if (data[1] == 1) { - *data = ui_InterruptStatus_1564; - } /* if (data[1]==1) */ - } /* else if (data[1]==0) */ return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[1] : 1 Enable VCC Interrupt | -| 0 Disable VCC Interrupt | -| data[2] : 1 Enable CC Interrupt | -| 0 Disable CC Interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * Configures The Digital Output Subdevice. + * + * data[1] 0 = Disable VCC Interrupt, 1 = Enable VCC Interrupt + * data[2] 0 = Disable CC Interrupt, 1 = Enable CC Interrupt + */ +static int apci1564_do_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ul_Command = 0; if ((data[0] != 0) && (data[0] != 1)) { comedi_error(dev, "Not a valid Data !!! ,Data should be 1 or 0\n"); return -EINVAL; - } /* if ((data[0]!=0) && (data[0]!=1)) */ - if (data[0]) { + } + + if (data[0]) devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } /* if (data[0]) */ - else { + else devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } /* else if (data[0]) */ - if (data[1] == ADDIDATA_ENABLE) { + + if (data[1] == ADDIDATA_ENABLE) ul_Command = ul_Command | 0x1; - } /* if (data[1] == ADDIDATA_ENABLE) */ - else { + else ul_Command = ul_Command & 0xFFFFFFFE; - } /* else if (data[1] == ADDIDATA_ENABLE) */ - if (data[2] == ADDIDATA_ENABLE) { + + if (data[2] == ADDIDATA_ENABLE) ul_Command = ul_Command | 0x2; - } /* if (data[2] == ADDIDATA_ENABLE) */ - else { + else ul_Command = ul_Command & 0xFFFFFFFD; - } /* else if (data[2] == ADDIDATA_ENABLE) */ - outl(ul_Command, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); - ui_InterruptData = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); - devpriv->tsk_Current = current; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To Write | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp, ui_Temp1; - unsigned int ui_NoOfChannel; - - ui_NoOfChannel = CR_CHAN(insn->chanspec); - if (devpriv->b_OutputMemoryStatus) { - ui_Temp = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - } /* if (devpriv->b_OutputMemoryStatus ) */ - else { - ui_Temp = 0; - } /* else if (devpriv->b_OutputMemoryStatus ) */ - if (data[3] == 0) { - if (data[1] == 0) { - data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; - outl(data[0], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - } /* if (data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - case 2: - data[0] = - (data[0] << (2 * - data[2])) | ui_Temp; - break; - case 4: - data[0] = - (data[0] << (4 * - data[2])) | ui_Temp; - break; - case 8: - data[0] = - (data[0] << (8 * - data[2])) | ui_Temp; - break; - case 16: - data[0] = - (data[0] << (16 * - data[2])) | ui_Temp; - break; - case 31: - data[0] = data[0] | ui_Temp; - break; - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* switch (ui_NoOfChannels) */ - outl(data[0], - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - } /* if (data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if (data[1]==1) */ - } /* else if (data[1]==0) */ - } /* if(data[3]==0) */ - else { - if (data[3] == 1) { - if (data[1] == 0) { - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - (data[0] << ui_NoOfChannel) ^ - 0xffffffff; - data[0] = data[0] & ui_Temp; - outl(data[0], - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - } /* if (data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - case 2: - data[0] = ~data[0] & 0x3; - ui_Temp1 = 3; - ui_Temp1 = - ui_Temp1 << 2 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (2 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - case 4: - data[0] = ~data[0] & 0xf; - ui_Temp1 = 15; - ui_Temp1 = - ui_Temp1 << 4 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (4 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - case 8: - data[0] = ~data[0] & 0xff; - ui_Temp1 = 255; - ui_Temp1 = - ui_Temp1 << 8 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (8 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - case 16: - data[0] = ~data[0] & 0xffff; - ui_Temp1 = 65535; - ui_Temp1 = - ui_Temp1 << 16 * - data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (16 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - case 31: - break; - default: - comedi_error(dev, - " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* switch(ui_NoOfChannels) */ - outl(data[0], - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - } /* if (data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if (data[1]==1) */ - } /* else if (data[1]==0) */ - } /* if (data[3]==1); */ - else { - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* else if (data[3]==1) */ - } /* else if (data[3]==0) */ - return insn->n; -} -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel or port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp; - unsigned int ui_NoOfChannel; - - ui_NoOfChannel = CR_CHAN(insn->chanspec); - ui_Temp = data[0]; - *data = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_RW); - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if (ui_Temp==0) */ - else { - if (ui_Temp == 1) { - switch (ui_NoOfChannel) { - case 2: - *data = (*data >> (2 * data[1])) & 3; - break; - - case 4: - *data = (*data >> (4 * data[1])) & 15; - break; - - case 8: - *data = (*data >> (8 * data[1])) & 255; - break; - - case 16: - *data = (*data >> (16 * data[1])) & 65535; - break; - - case 31: - break; - - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - break; - } /* switch(ui_NoOfChannels) */ - } /* if (ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* else if (ui_Temp==1) */ - } /* else if (ui_Temp==0) */ + outl(ul_Command, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + ui_InterruptData = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + devpriv->tsk_Current = current; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ConfigTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Counter | -| 2 Configure As Watchdog | -| data[1] : 1 Enable Interrupt | -| 0 Disable Interrupt | -| data[2] : Time Unit | -| data[3] : Reload Value | -| data[4] : Timer Mode | -| data[5] : Timer Counter Watchdog Number| - data[6] : Counter Direction -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) + * Configures The Timer, Counter or Watchdog + * + * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[1] 1 = Enable Interrupt, 0 = Disable Interrupt + * data[2] Time Unit + * data[3] Reload Value + * data[4] Timer Mode + * data[5] Timer Counter Watchdog Number + * data[6] Counter Direction + */ +static int apci1564_timer_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; + devpriv->tsk_Current = current; if (data[0] == ADDIDATA_WATCHDOG) { devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG; /* Disable the watchdog */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); /* Loading the Reload value */ - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_RELOAD_VALUE); - } /* if (data[0]==ADDIDATA_WATCHDOG) */ - else if (data[0] == ADDIDATA_TIMER) { + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_WDOG_RELOAD_REG); + } else if (data[0] == ADDIDATA_TIMER) { /* First Stop The Timer */ - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Stop The Timer */ + /* Stop The Timer */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (data[1] == 1) { - outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ + /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ + outl(0x02, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_IRQ_REG); outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_IRQ); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_IRQ); + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_IRQ); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_IRQ); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_IRQ); - outl(0x0, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_IRQ); - } /* if (data[1]==1) */ - else { - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* disable Timer interrupt */ - } /* else if (data[1]==1) */ + dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)); + } else { + /* disable Timer interrupt */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } /* Loading Timebase */ - - outl(data[2], - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_TIMEBASE); + outl(data[2], devpriv->i_IobaseAmcc + APCI1564_TIMER_TIMEBASE_REG); /* Loading the Reload value */ - outl(data[3], - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_RELOAD_VALUE); + outl(data[3], devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG); - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - ul_Command1 = - (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); /* mode 2 */ - } /* else if (data[0]==ADDIDATA_TIMER) */ - else if (data[0] == ADDIDATA_COUNTER) { + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; + /* mode 2 */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } else if (data[0] == ADDIDATA_COUNTER) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; devpriv->b_ModeSelectRegister = data[5]; /* First Stop The Counter */ - ul_Command1 = - inl(devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->iobase + ((data[5] - 1) * 0x20) + APCI1564_TCW_PROG); /* Stop The Timer */ + /* Stop The Timer */ + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); - /************************/ /* Set the reload value */ - /************************/ - outl(data[3], - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_RELOAD_VALUE); + outl(data[3], dev->iobase + APCI1564_TCW_RELOAD_REG(data[5] - 1)); - /******************************/ /* Set the mode : */ /* - Disable the hardware */ /* - Disable the counter mode */ @@ -665,339 +254,223 @@ int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, /* - Disable the reset */ /* - Disable the timer mode */ /* - Enable the counter mode */ - /******************************/ + ul_Command1 = (ul_Command1 & 0xFFFC19E2UL) | 0x80000UL | (unsigned int) ((unsigned int) data[4] << 16UL); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); /* Enable or Disable Interrupt */ ul_Command1 = (ul_Command1 & 0xFFFFF9FD) | (data[1] << 1); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); - /*****************************/ /* Set the Up/Down selection */ - /*****************************/ ul_Command1 = (ul_Command1 & 0xFFFBF9FFUL) | (data[6] << 18); - outl(ul_Command1, - devpriv->iobase + ((data[5] - 1) * 0x20) + - APCI1564_TCW_PROG); - } /* else if (data[0]==ADDIDATA_COUNTER) */ - else { - printk(" Invalid subdevice."); - } /* else if (data[0]==ADDIDATA_WATCHDOG) */ + outl(ul_Command1, dev->iobase + APCI1564_TCW_CTRL_REG(data[5] - 1)); + } else { + dev_err(dev->class_dev, "Invalid subdevice.\n"); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_StartStopWriteTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Timer | -| 1 Counter | -| 2 Watchdog | | data[1] : 1 Start | -| 0 Stop | -| 2 Trigger | -| Clear (Only Counter) | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) + * Start / Stop The Selected Timer, Counter or Watchdog + * + * data[0] Configure as: 0 = Timer, 1 = Counter, 2 = Watchdog + * data[1] 0 = Stop, 1 = Start, 2 = Trigger Clear (Only Counter) + */ +static int apci1564_timer_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { switch (data[1]) { case 0: /* stop the watchdog */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + APCI1564_TCW_PROG); /* disable the watchdog */ + /* disable the watchdog */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; case 1: /* start the watchdog */ - outl(0x0001, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0001, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; case 2: /* Software trigger */ - outl(0x0201, - devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_PROG); + outl(0x0201, devpriv->i_IobaseAmcc + APCI1564_WDOG_CTRL_REG); break; default: - printk("\nSpecified functionality does not exist\n"); + dev_err(dev->class_dev, "Specified functionality does not exist.\n"); return -EINVAL; - } /* switch (data[1]) */ - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { if (data[1] == 1) { - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Timer */ - outl(ul_Command1, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } /* if (data[1]==1) */ - else if (data[1] == 0) { + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } else if (data[1] == 0) { /* Stop The Timer */ - ul_Command1 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command1 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - } /* else if(data[1]==0) */ - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ + outl(ul_Command1, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { ul_Command1 = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_PROG); + inl(dev->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); if (data[1] == 1) { /* Start the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; - } /* if (data[1] == 1) */ - else if (data[1] == 0) { + } else if (data[1] == 0) { /* Stops the Counter subdevice */ ul_Command1 = 0; - } /* else if (data[1] == 0) */ - else if (data[1] == 2) { + } else if (data[1] == 2) { /* Clears the Counter subdevice */ ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x400; - } /* else if (data[1] == 3) */ - outl(ul_Command1, - devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_PROG); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ + } + outl(ul_Command1, dev->iobase + + APCI1564_TCW_CTRL_REG(devpriv->b_ModeSelectRegister - 1)); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | - -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) + * Read The Selected Timer, Counter or Watchdog + */ +static int apci1564_timer_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ul_Command1 = 0; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { /* Stores the status of the Watchdog */ - data[0] = - inl(devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_TRIG_STATUS) & 0x1; - data[1] = - inl(devpriv->i_IobaseAmcc + - APCI1564_DIGITAL_OP_WATCHDOG); - } /* if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ - else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { + data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_STATUS_REG) & 0x1; + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { /* Stores the status of the Timer */ - data[0] = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_TRIG_STATUS) & 0x1; + data[0] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_STATUS_REG) & 0x1; /* Stores the Actual value of the Timer */ - data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER); - } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_COUNTER) { /* Read the Counter Actual Value. */ data[0] = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + - APCI1564_TCW_SYNC_ENABLEDISABLE); + inl(dev->iobase + + APCI1564_TCW_REG(devpriv->b_ModeSelectRegister - 1)); ul_Command1 = - inl(devpriv->iobase + ((devpriv->b_ModeSelectRegister - - 1) * 0x20) + APCI1564_TCW_TRIG_STATUS); + inl(dev->iobase + + APCI1564_TCW_STATUS_REG(devpriv->b_ModeSelectRegister - 1)); - /***********************************/ /* Get the software trigger status */ - /***********************************/ data[1] = (unsigned char) ((ul_Command1 >> 1) & 1); - /***********************************/ /* Get the hardware trigger status */ - /***********************************/ data[2] = (unsigned char) ((ul_Command1 >> 2) & 1); - /*********************************/ /* Get the software clear status */ - /*********************************/ data[3] = (unsigned char) ((ul_Command1 >> 3) & 1); - /***************************/ /* Get the overflow status */ - /***************************/ data[4] = (unsigned char) ((ul_Command1 >> 0) & 1); - } /* else if (devpriv->b_TimerSelectMode==ADDIDATA_COUNTER) */ - else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) + } else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG) && (devpriv->b_TimerSelectMode != ADDIDATA_COUNTER)) { - printk("\n Invalid Subdevice !!!\n"); - } /* else if ((devpriv->b_TimerSelectMode!=ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode!=ADDIDATA_WATCHDOG)&& (devpriv->b_TimerSelectMode!=ADDIDATA_COUNTER)) */ + dev_err(dev->class_dev, "Invalid Subdevice!\n"); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_ReadInterruptStatus | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task :Reads the interrupt status register | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * Reads the interrupt status register + */ +static int apci1564_do_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { *data = ui_Type; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI1564_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt handler for the interruptible digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -static void v_APCI1564_Interrupt(int irq, void *d) + * Interrupt handler for the interruptible digital inputs + */ +static void apci1564_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct addi_private *devpriv = dev->private; unsigned int ui_DO, ui_DI; unsigned int ui_Timer; unsigned int ui_C1, ui_C2, ui_C3, ui_C4; unsigned int ul_Command2 = 0; - ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ) & 0x01; - ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_IRQ) & 0x01; - ui_Timer = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_IRQ) & 0x01; - ui_C1 = inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_IRQ) & 0x1; - ui_C2 = inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_IRQ) & 0x1; - ui_C3 = inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_IRQ) & 0x1; - ui_C4 = inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_IRQ) & 0x1; + + ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG) & 0x01; + ui_DO = inl(devpriv->i_IobaseAmcc + APCI1564_DO_IRQ_REG) & 0x01; + ui_Timer = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_IRQ_REG) & 0x01; + ui_C1 = + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER1)) & 0x1; + ui_C2 = + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER2)) & 0x1; + ui_C3 = + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER3)) & 0x1; + ui_C4 = + inl(dev->iobase + APCI1564_TCW_IRQ_REG(APCI1564_COUNTER4)) & 0x1; if (ui_DI == 0 && ui_DO == 0 && ui_Timer == 0 && ui_C1 == 0 && ui_C2 == 0 && ui_C3 == 0 && ui_C4 == 0) { - printk("\nInterrupt from unknown source\n"); - } /* if(ui_DI==0 && ui_DO==0 && ui_Timer==0 && ui_C1==0 && ui_C2==0 && ui_C3==0 && ui_C4==0) */ + dev_err(dev->class_dev, "Interrupt from unknown source.\n"); + } if (ui_DI == 1) { - ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_IRQ); + ui_DI = inl(devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); ui_InterruptStatus_1564 = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + - APCI1564_DIGITAL_IP_INTERRUPT_STATUS); + inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); ui_InterruptStatus_1564 = ui_InterruptStatus_1564 & 0X000FFFF0; - send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */ - outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP + APCI1564_DIGITAL_IP_IRQ); /* enable the interrupt */ + /* send signal to the sample */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + /* enable the interrupt */ + outl(ui_DI, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); return; } if (ui_DO == 1) { - /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */ - ui_Type = - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT_STATUS) & 0x3; + /* Check for Digital Output interrupt Type */ + /* 1: VCC interrupt */ + /* 2: CC interrupt */ + ui_Type = inl(devpriv->i_IobaseAmcc + APCI1564_DO_INT_STATUS_REG) & 0x3; /* Disable the Interrupt */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP + - APCI1564_DIGITAL_OP_INTERRUPT); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); /* Sends signal to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); - - } /* if (ui_DO) */ + } if (ui_Timer == 1) { devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (devpriv->b_TimerSelectMode) { /* Disable Timer Interrupt */ - ul_Command2 = - inl(devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + ul_Command2 = inl(devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Timer Interrupt */ - outl(ul_Command2, - devpriv->i_IobaseAmcc + APCI1564_TIMER + - APCI1564_TCW_PROG); + outl(ul_Command2, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); } - }/* if (ui_Timer == 1) */ - + } if (ui_C1 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -1005,21 +478,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER1 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); } - } /* if (ui_C1 == 1) */ + } if (ui_C2 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -1027,21 +497,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER2 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); } - } /* if ((ui_C2 == 1) */ + } if (ui_C3 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -1049,21 +516,18 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER3 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); } - } /* if ((ui_C3 == 1) */ + } if (ui_C4 == 1) { devpriv->b_TimerSelectMode = ADDIDATA_COUNTER; @@ -1071,58 +535,17 @@ static void v_APCI1564_Interrupt(int irq, void *d) /* Disable Counter Interrupt */ ul_Command2 = - inl(devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + inl(dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); outl(0x0, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); /* Send a signal to from kernel to user space */ send_sig(SIGIO, devpriv->tsk_Current, 0); /* Enable Counter Interrupt */ outl(ul_Command2, - devpriv->iobase + APCI1564_COUNTER4 + - APCI1564_TCW_PROG); + dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); } - } /* if (ui_C4 == 1) */ + } return; } - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI1564_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI1564_Reset(struct comedi_device *dev) -{ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_IRQ); /* disable the interrupts */ - inl(devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_STATUS); /* Reset the interrupt status register */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE1); /* Disable the and/or interrupt */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_IP_INTERRUPT_MODE2); - devpriv->b_DigitalOutputRegister = 0; - ui_Type = 0; - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP); /* Resets the output channels */ - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */ - outl(0x0, - devpriv->i_IobaseAmcc + APCI1564_DIGITAL_OP_WATCHDOG + - APCI1564_TCW_RELOAD_VALUE); - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER); - outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER + APCI1564_TCW_PROG); - - outl(0x0, devpriv->iobase + APCI1564_COUNTER1 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER2 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER3 + APCI1564_TCW_PROG); - outl(0x0, devpriv->iobase + APCI1564_COUNTER4 + APCI1564_TCW_PROG); - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h deleted file mode 100644 index c91594d56a4..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1564.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * 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. - */ - -/********* Definitions for APCI-1564 card *****/ - -#define APCI1564_BOARD_VENDOR_ID 0x15B8 -#define APCI1564_ADDRESS_RANGE 128 - -/* DIGITAL INPUT-OUTPUT DEFINE */ -/* Input defines */ -#define APCI1564_DIGITAL_IP 0x04 -#define APCI1564_DIGITAL_IP_INTERRUPT_MODE1 4 -#define APCI1564_DIGITAL_IP_INTERRUPT_MODE2 8 -#define APCI1564_DIGITAL_IP_IRQ 16 - -/* Output defines */ -#define APCI1564_DIGITAL_OP 0x18 -#define APCI1564_DIGITAL_OP_RW 0 -#define APCI1564_DIGITAL_OP_INTERRUPT 4 -#define APCI1564_DIGITAL_OP_IRQ 12 - -/* Digital Input IRQ Function Selection */ -#define ADDIDATA_OR 0 -#define ADDIDATA_AND 1 - -/* Digital Input Interrupt Status */ -#define APCI1564_DIGITAL_IP_INTERRUPT_STATUS 12 - -/* Digital Output Interrupt Status */ -#define APCI1564_DIGITAL_OP_INTERRUPT_STATUS 8 - -/* Digital Input Interrupt Enable Disable. */ -#define APCI1564_DIGITAL_IP_INTERRUPT_ENABLE 0x4 -#define APCI1564_DIGITAL_IP_INTERRUPT_DISABLE 0xFFFFFFFB - -/* 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 - -/* ADDIDATA Enable Disable */ - -#define ADDIDATA_ENABLE 1 -#define ADDIDATA_DISABLE 0 - -/* TIMER COUNTER WATCHDOG DEFINES */ - -#define ADDIDATA_TIMER 0 -#define ADDIDATA_COUNTER 1 -#define ADDIDATA_WATCHDOG 2 -#define APCI1564_DIGITAL_OP_WATCHDOG 0x28 -#define APCI1564_TIMER 0x48 -#define APCI1564_COUNTER1 0x0 -#define APCI1564_COUNTER2 0x20 -#define APCI1564_COUNTER3 0x40 -#define APCI1564_COUNTER4 0x60 -#define APCI1564_TCW_SYNC_ENABLEDISABLE 0 -#define APCI1564_TCW_RELOAD_VALUE 4 -#define APCI1564_TCW_TIMEBASE 8 -#define APCI1564_TCW_PROG 12 -#define APCI1564_TCW_TRIG_STATUS 16 -#define APCI1564_TCW_IRQ 20 -#define APCI1564_TCW_WARN_TIMEVAL 24 -#define APCI1564_TCW_WARN_TIMEBASE 28 - -/* Hardware Layer functions for Apci1564 */ - -/* -* DI for di read -*/ -int i_APCI1564_ConfigDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1564_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1564_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* DO */ -int i_APCI1564_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1564_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1564_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1564_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* -* TIMER timer value is passed as u seconds -*/ -int i_APCI1564_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI1564_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -int i_APCI1564_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* intERRUPT */ -static void v_APCI1564_Interrupt(int irq, void *d); - -/* RESET */ -int i_APCI1564_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c deleted file mode 100644 index 00a088f820a..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.c +++ /dev/null @@ -1,780 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : API APCI1648 | Compiler : gcc | - | Module name : TTL.C | Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: S. Weber | Date : 25/05/2005 | - +-----------------------------------------------------------------------+ - | Description : APCI-16XX TTL I/O module | - | | - | | - +-----------------------------------------------------------------------+ - | UPDATES | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - |25.05.2005| S.Weber | Creation | - | | | | - +-----------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ - -#include "hwdrv_apci16xx.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI16XX_InsnConfigInitTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task APCI16XX_TTL_INIT (using defaults) : | -| Configure the TTL I/O operating mode from all ports | -| You must calling this function be | -| for you call any other function witch access of TTL. | -| APCI16XX_TTL_INITDIRECTION(user inputs for direction) | -+----------------------------------------------------------------------------+ -| Input Parameters : b_InitType = (unsigned char) data[0]; | -| b_Port0Mode = (unsigned char) data[1]; | -| b_Port1Mode = (unsigned char) data[2]; | -| b_Port2Mode = (unsigned char) data[3]; | -| b_Port3Mode = (unsigned char) data[4]; | -| ........ | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -1: Port 0 mode selection is wrong | -| -2: Port 1 mode selection is wrong | -| -3: Port 2 mode selection is wrong | -| -4: Port 3 mode selection is wrong | -| -X: Port X-1 mode selection is wrong | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Command = 0; - unsigned char b_Cpt = 0; - unsigned char b_NumberOfPort = - (unsigned char) (this_board->i_NbrTTLChannel / 8); - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) data[0]; - - /********************/ - /* Test the command */ - /********************/ - - if ((b_Command == APCI16XX_TTL_INIT) || - (b_Command == APCI16XX_TTL_INITDIRECTION) || - (b_Command == APCI16XX_TTL_OUTPUTMEMORY)) { - /***************************************/ - /* Test the initialisation buffer size */ - /***************************************/ - - if ((b_Command == APCI16XX_TTL_INITDIRECTION) - && ((unsigned char) (insn->n - 1) != b_NumberOfPort)) { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - - if ((b_Command == APCI16XX_TTL_OUTPUTMEMORY) - && ((unsigned char) (insn->n) != 2)) { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("\nCommand selection error"); - i_ReturnValue = -100; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - - /**************************************************************************/ - /* Test if no error occur and APCI16XX_TTL_INITDIRECTION command selected */ - /**************************************************************************/ - - if ((i_ReturnValue >= 0) && (b_Command == APCI16XX_TTL_INITDIRECTION)) { - memset(devpriv->ul_TTLPortConfiguration, 0, - sizeof(devpriv->ul_TTLPortConfiguration)); - - /*************************************/ - /* Test the port direction selection */ - /*************************************/ - - for (b_Cpt = 1; - (b_Cpt <= b_NumberOfPort) && (i_ReturnValue >= 0); - b_Cpt++) { - /**********************/ - /* Test the direction */ - /**********************/ - - if ((data[b_Cpt] != 0) && (data[b_Cpt] != 0xFF)) { - /************************/ - /* Port direction error */ - /************************/ - - printk("\nPort %d direction selection error", - (int) b_Cpt); - i_ReturnValue = -(int) b_Cpt; - } - - /**************************/ - /* Save the configuration */ - /**************************/ - - devpriv->ul_TTLPortConfiguration[(b_Cpt - 1) / 4] = - devpriv->ul_TTLPortConfiguration[(b_Cpt - - 1) / 4] | (data[b_Cpt] << (8 * ((b_Cpt - - 1) % 4))); - } - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - /***********************************/ - /* Test if TTL port initilaisation */ - /***********************************/ - - if ((b_Command == APCI16XX_TTL_INIT) - || (b_Command == APCI16XX_TTL_INITDIRECTION)) { - /******************************/ - /* Set all port configuration */ - /******************************/ - - for (b_Cpt = 0; b_Cpt <= b_NumberOfPort; b_Cpt++) { - if ((b_Cpt % 4) == 0) { - /*************************/ - /* Set the configuration */ - /*************************/ - - outl(devpriv-> - ul_TTLPortConfiguration[b_Cpt / - 4], - devpriv->iobase + 32 + b_Cpt); - } - } - } - } - - /************************************************/ - /* Test if output memory initialisation command */ - /************************************************/ - - if (b_Command == APCI16XX_TTL_OUTPUTMEMORY) { - if (data[1]) { - devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } else { - devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI16XX_InsnBitsReadTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the status from selected TTL digital input | -| (b_InputChannel) | -+----------------------------------------------------------------------------+ -| Task : Read the status from digital input port | -| (b_SelectedPort) | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| APCI16XX_TTL_READCHANNEL | -| b_SelectedPort= CR_RANGE(insn->chanspec); | -| b_InputChannel= CR_CHAN(insn->chanspec); | -| b_ReadType = (unsigned char) data[0]; | -| | -| APCI16XX_TTL_READPORT | -| b_SelectedPort= CR_RANGE(insn->chanspec); | -| b_ReadType = (unsigned char) data[0]; | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] 0 : Channle is not active | -| 1 : Channle is active | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -100 : Config command error | -| -101 : Data size error | -| -102 : The selected TTL input port is wrong | -| -103 : The selected TTL digital input is wrong | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Command = 0; - unsigned char b_NumberOfPort = - (unsigned char) (this_board->i_NbrTTLChannel / 8); - unsigned char b_SelectedPort = CR_RANGE(insn->chanspec); - unsigned char b_InputChannel = CR_CHAN(insn->chanspec); - unsigned char *pb_Status; - unsigned int dw_Status; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) data[0]; - - /********************/ - /* Test the command */ - /********************/ - - if ((b_Command == APCI16XX_TTL_READCHANNEL) - || (b_Command == APCI16XX_TTL_READPORT)) { - /**************************/ - /* Test the selected port */ - /**************************/ - - if (b_SelectedPort < b_NumberOfPort) { - /**********************/ - /* Test if input port */ - /**********************/ - - if (((devpriv->ul_TTLPortConfiguration - [b_SelectedPort / - 4] >> (8 * - (b_SelectedPort - % - 4))) & - 0xFF) == 0) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if ((b_Command == - APCI16XX_TTL_READCHANNEL) - && (b_InputChannel > 7)) { - /*******************************************/ - /* The selected TTL digital input is wrong */ - /*******************************************/ - - printk("\nChannel selection error"); - i_ReturnValue = -103; - } - } else { - /****************************************/ - /* The selected TTL input port is wrong */ - /****************************************/ - - printk("\nPort selection error"); - i_ReturnValue = -102; - } - } else { - /****************************************/ - /* The selected TTL input port is wrong */ - /****************************************/ - - printk("\nPort selection error"); - i_ReturnValue = -102; - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("\nCommand selection error"); - i_ReturnValue = -100; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - pb_Status = (unsigned char *) &data[0]; - - /*******************************/ - /* Get the digital inpu status */ - /*******************************/ - - dw_Status = - inl(devpriv->iobase + 8 + ((b_SelectedPort / 4) * 4)); - dw_Status = (dw_Status >> (8 * (b_SelectedPort % 4))) & 0xFF; - - /***********************/ - /* Save the port value */ - /***********************/ - - *pb_Status = (unsigned char) dw_Status; - - /***************************************/ - /* Test if read channel status command */ - /***************************************/ - - if (b_Command == APCI16XX_TTL_READCHANNEL) { - *pb_Status = (*pb_Status >> b_InputChannel) & 1; - } - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI16XX_InsnReadTTLIOAllPortValue | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the status from all digital input ports | -+----------------------------------------------------------------------------+ -| Input Parameters : - | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : Port 0 to 3 data | -| data[1] : Port 4 to 7 data | -| .... | -+----------------------------------------------------------------------------+ -| Return Value : 0: No error | -| -100 : Read command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - unsigned char b_Command = (unsigned char) CR_AREF(insn->chanspec); - int i_ReturnValue = insn->n; - unsigned char b_Cpt = 0; - unsigned char b_NumberOfPort = 0; - unsigned int *pls_ReadData = data; - - /********************/ - /* Test the command */ - /********************/ - - if ((b_Command == APCI16XX_TTL_READ_ALL_INPUTS) - || (b_Command == APCI16XX_TTL_READ_ALL_OUTPUTS)) { - /**********************************/ - /* Get the number of 32-Bit ports */ - /**********************************/ - - b_NumberOfPort = - (unsigned char) (this_board->i_NbrTTLChannel / 32); - if ((b_NumberOfPort * 32) < - this_board->i_NbrTTLChannel) { - b_NumberOfPort = b_NumberOfPort + 1; - } - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= b_NumberOfPort) { - if (b_Command == APCI16XX_TTL_READ_ALL_INPUTS) { - /**************************/ - /* Read all digital input */ - /**************************/ - - for (b_Cpt = 0; b_Cpt < b_NumberOfPort; b_Cpt++) { - /************************/ - /* Read the 32-Bit port */ - /************************/ - - pls_ReadData[b_Cpt] = - inl(devpriv->iobase + 8 + - (b_Cpt * 4)); - - /**************************************/ - /* Mask all channels used als outputs */ - /**************************************/ - - pls_ReadData[b_Cpt] = - pls_ReadData[b_Cpt] & - (~devpriv-> - ul_TTLPortConfiguration[b_Cpt]); - } - } else { - /****************************/ - /* Read all digital outputs */ - /****************************/ - - for (b_Cpt = 0; b_Cpt < b_NumberOfPort; b_Cpt++) { - /************************/ - /* Read the 32-Bit port */ - /************************/ - - pls_ReadData[b_Cpt] = - inl(devpriv->iobase + 20 + - (b_Cpt * 4)); - - /**************************************/ - /* Mask all channels used als outputs */ - /**************************************/ - - pls_ReadData[b_Cpt] = - pls_ReadData[b_Cpt] & devpriv-> - ul_TTLPortConfiguration[b_Cpt]; - } - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - } else { - /*****************/ - /* Command error */ - /*****************/ - - printk("\nCommand selection error"); - i_ReturnValue = -100; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI16XX_InsnBitsWriteTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Set the state from selected TTL digital output | -| (b_OutputChannel) | -+----------------------------------------------------------------------------+ -| Task : Set the state from digital output port | -| (b_SelectedPort) | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| APCI16XX_TTL_WRITECHANNEL_ON | APCI16XX_TTL_WRITECHANNEL_OFF | -| b_SelectedPort = CR_RANGE(insn->chanspec); | -| b_OutputChannel= CR_CHAN(insn->chanspec); | -| b_Command = (unsigned char) data[0]; | -| | -| APCI16XX_TTL_WRITEPORT_ON | APCI16XX_TTL_WRITEPORT_OFF | -| b_SelectedPort = CR_RANGE(insn->chanspec); | -| b_Command = (unsigned char) data[0]; | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : TTL output port 0 to 3 data | -| data[1] : TTL output port 4 to 7 data | -| .... | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -100 : Command error | -| -101 : Data size error | -| -102 : The selected TTL output port is wrong | -| -103 : The selected TTL digital output is wrong | -| -104 : Output memory disabled | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Command = 0; - unsigned char b_NumberOfPort = - (unsigned char) (this_board->i_NbrTTLChannel / 8); - unsigned char b_SelectedPort = CR_RANGE(insn->chanspec); - unsigned char b_OutputChannel = CR_CHAN(insn->chanspec); - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) data[0]; - - /********************/ - /* Test the command */ - /********************/ - - if ((b_Command == APCI16XX_TTL_WRITECHANNEL_ON) || - (b_Command == APCI16XX_TTL_WRITEPORT_ON) || - (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) || - (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) { - /**************************/ - /* Test the selected port */ - /**************************/ - - if (b_SelectedPort < b_NumberOfPort) { - /***********************/ - /* Test if output port */ - /***********************/ - - if (((devpriv->ul_TTLPortConfiguration - [b_SelectedPort / - 4] >> (8 * - (b_SelectedPort - % - 4))) & - 0xFF) == 0xFF) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if (((b_Command == APCI16XX_TTL_WRITECHANNEL_ON) || (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF)) && (b_OutputChannel > 7)) { - /********************************************/ - /* The selected TTL digital output is wrong */ - /********************************************/ - - printk("\nChannel selection error"); - i_ReturnValue = -103; - } - - if (((b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) || (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) && (devpriv->b_OutputMemoryStatus == ADDIDATA_DISABLE)) { - /********************************************/ - /* The selected TTL digital output is wrong */ - /********************************************/ - - printk("\nOutput memory disabled"); - i_ReturnValue = -104; - } - - /************************/ - /* Test the buffer size */ - /************************/ - - if (((b_Command == APCI16XX_TTL_WRITEPORT_ON) || (b_Command == APCI16XX_TTL_WRITEPORT_OFF)) && (insn->n < 2)) { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - } else { - /*****************************************/ - /* The selected TTL output port is wrong */ - /*****************************************/ - - printk("\nPort selection error %lX", - (unsigned long)devpriv-> - ul_TTLPortConfiguration[0]); - i_ReturnValue = -102; - } - } else { - /****************************************/ - /* The selected TTL output port is wrong */ - /****************************************/ - - printk("\nPort selection error %d %d", - b_SelectedPort, b_NumberOfPort); - i_ReturnValue = -102; - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("\nCommand selection error"); - i_ReturnValue = -100; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("\nBuffer size error"); - i_ReturnValue = -101; - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - /********************************/ - /* Get the digital output state */ - /********************************/ - - dw_Status = - inl(devpriv->iobase + 20 + ((b_SelectedPort / 4) * 4)); - - /**********************************/ - /* Test if output memory not used */ - /**********************************/ - - if (devpriv->b_OutputMemoryStatus == ADDIDATA_DISABLE) { - /*********************************/ - /* Clear the selected port value */ - /*********************************/ - - dw_Status = - dw_Status & (0xFFFFFFFFUL - - (0xFFUL << (8 * (b_SelectedPort % 4)))); - } - - /******************************/ - /* Test if setting channel ON */ - /******************************/ - - if (b_Command == APCI16XX_TTL_WRITECHANNEL_ON) { - dw_Status = - dw_Status | (1UL << ((8 * (b_SelectedPort % - 4)) + b_OutputChannel)); - } - - /***************************/ - /* Test if setting port ON */ - /***************************/ - - if (b_Command == APCI16XX_TTL_WRITEPORT_ON) { - dw_Status = - dw_Status | ((data[1] & 0xFF) << (8 * - (b_SelectedPort % 4))); - } - - /*******************************/ - /* Test if setting channel OFF */ - /*******************************/ - - if (b_Command == APCI16XX_TTL_WRITECHANNEL_OFF) { - dw_Status = - dw_Status & (0xFFFFFFFFUL - - (1UL << ((8 * (b_SelectedPort % 4)) + - b_OutputChannel))); - } - - /****************************/ - /* Test if setting port OFF */ - /****************************/ - - if (b_Command == APCI16XX_TTL_WRITEPORT_OFF) { - dw_Status = - dw_Status & (0xFFFFFFFFUL - - ((data[1] & 0xFF) << (8 * (b_SelectedPort % - 4)))); - } - - outl(dw_Status, - devpriv->iobase + 20 + ((b_SelectedPort / 4) * 4)); - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_Reset(struct comedi_device *dev) | +----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : - | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI16XX_Reset(struct comedi_device *dev) -{ - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.h deleted file mode 100644 index 5bf91e13a03..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci16xx.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * 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. - */ - -#ifndef COMEDI_SUBD_TTLIO -#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ -#endif - -#ifndef ADDIDATA_ENABLE -#define ADDIDATA_ENABLE 1 -#define ADDIDATA_DISABLE 0 -#endif - -#define APCI16XX_TTL_INIT 0 -#define APCI16XX_TTL_INITDIRECTION 1 -#define APCI16XX_TTL_OUTPUTMEMORY 2 - -#define APCI16XX_TTL_READCHANNEL 0 -#define APCI16XX_TTL_READPORT 1 - -#define APCI16XX_TTL_WRITECHANNEL_ON 0 -#define APCI16XX_TTL_WRITECHANNEL_OFF 1 -#define APCI16XX_TTL_WRITEPORT_ON 2 -#define APCI16XX_TTL_WRITEPORT_OFF 3 - -#define APCI16XX_TTL_READ_ALL_INPUTS 0 -#define APCI16XX_TTL_READ_ALL_OUTPUTS 1 - -#ifdef __KERNEL__ - -static const struct comedi_lrange range_apci16xx_ttl = { 12, - {BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1)} -}; - -/* -+----------------------------------------------------------------------------+ -| TTL INISIALISATION FUNCTION | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI16XX_InsnConfigInitTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); - -/* -+----------------------------------------------------------------------------+ -| TTL INPUT FUNCTION | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI16XX_InsnBitsReadTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); - -int i_APCI16XX_InsnReadTTLIOAllPortValue(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* -+----------------------------------------------------------------------------+ -| TTL OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI16XX_InsnBitsWriteTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); - -int i_APCI16XX_Reset(struct comedi_device *dev); -#endif diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c deleted file mode 100644 index 49dcbe24fcd..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.c +++ /dev/null @@ -1,460 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-2016 | Compiler : GCC | - | Module name : hwdrv_apci2016.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-2016 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ -#include "hwdrv_apci2016.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2016_ConfigDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 1 Digital Memory On | -| 0 Digital Memory Off | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2016_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if ((data[0] != 0) && (data[0] != 1)) { - comedi_error(dev, - "Not a valid Data !!! ,Data should be 1 or 0\n"); - return -EINVAL; - } /* if ((data[0]!=0) && (data[0]!=1)) */ - if (data[0]) { - devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } /* if (data[0] */ - else { - devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } /* else if (data[0] */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2016_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To Write | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2016_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_NoOfChannel; - unsigned int ui_Temp, ui_Temp1; - ui_NoOfChannel = CR_CHAN(insn->chanspec); - if (ui_NoOfChannel > 15) { - comedi_error(dev, - "Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n"); - return -EINVAL; - } /* if ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) */ - if (devpriv->b_OutputMemoryStatus) { - ui_Temp = inw(devpriv->iobase + APCI2016_DIGITAL_OP); - } /* if (devpriv->b_OutputMemoryStatus ) */ - else { - ui_Temp = 0; - } /* else if (devpriv->b_OutputMemoryStatus ) */ - if ((data[1] != 0) && (data[1] != 1)) { - comedi_error(dev, - "Invalid Data[1] value !!!, Data[1] should be 0 or 1\n"); - return -EINVAL; - } /* if ((data[1]!=0) && (data[1]!=1)) */ - - if (data[3] == 0) { - if (data[1] == 0) { - data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; - outw(data[0], devpriv->iobase + APCI2016_DIGITAL_OP); - } /* if (data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - case 2: - data[0] = - (data[0] << (2 * - data[2])) | ui_Temp; - break; - case 4: - data[0] = - (data[0] << (4 * - data[2])) | ui_Temp; - break; - case 8: - data[0] = - (data[0] << (8 * - data[2])) | ui_Temp; - break; - case 15: - data[0] = data[0] | ui_Temp; - break; - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* switch(ui_NoOfChannels) */ - outw(data[0], - devpriv->iobase + APCI2016_DIGITAL_OP); - } /* if (data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if (data[1]==1) */ - } /* else if (data[1]==0) */ - } /* if (data[3]==0) */ - else { - if (data[3] == 1) { - if (data[1] == 0) { - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = (data[0] << ui_NoOfChannel) ^ 0xffff; - data[0] = data[0] & ui_Temp; - outw(data[0], - devpriv->iobase + APCI2016_DIGITAL_OP); - } /* if (data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - case 2: - data[0] = ~data[0] & 0x3; - ui_Temp1 = 3; - ui_Temp1 = - ui_Temp1 << 2 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (2 * - data - [2])) ^ - 0xffff) & ui_Temp; - break; - case 4: - data[0] = ~data[0] & 0xf; - ui_Temp1 = 15; - ui_Temp1 = - ui_Temp1 << 4 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (4 * - data - [2])) ^ - 0xffff) & ui_Temp; - break; - case 8: - data[0] = ~data[0] & 0xff; - ui_Temp1 = 255; - ui_Temp1 = - ui_Temp1 << 8 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (8 * - data - [2])) ^ - 0xffff) & ui_Temp; - break; - case 15: - break; - default: - comedi_error(dev, - " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* switch(ui_NoOfChannels) */ - outw(data[0], - devpriv->iobase + - APCI2016_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==1); */ - else { - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* if else data[3]==1) */ - } /* if else data[3]==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2016_BitsDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel or port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2016_BitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp; - unsigned int ui_NoOfChannel; - ui_NoOfChannel = CR_CHAN(insn->chanspec); - if (ui_NoOfChannel > 15) { - comedi_error(dev, - "Invalid Channel Numbers !!!, Channel Numbers must be between 0 and 15\n"); - return -EINVAL; - } /* if ((ui_NoOfChannel<0) || (ui_NoOfChannel>15)) */ - if ((data[0] != 0) && (data[0] != 1)) { - comedi_error(dev, - "Invalid Data[0] value !!!, Data[0] should be 0 or 1\n"); - return -EINVAL; - } /* if ((data[0]!=0) && (data[0]!=1)) */ - ui_Temp = data[0]; - *data = inw(devpriv->iobase + APCI2016_DIGITAL_OP_RW); - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if (ui_Temp==0) */ - else { - if (ui_Temp == 1) { - switch (ui_NoOfChannel) { - case 2: - *data = (*data >> (2 * data[1])) & 3; - break; - - case 4: - *data = (*data >> (4 * data[1])) & 15; - break; - - case 8: - *data = (*data >> (8 * data[1])) & 255; - break; - - case 15: - break; - - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* switch(ui_NoOfChannel) */ - } /* if (ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* else if (ui_Temp==1) */ - } /* if (ui_Temp==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2016_ConfigWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure | -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2016_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - if (data[0] == 0) { - /* Disable the watchdog */ - outw(0x0, - devpriv->i_IobaseAddon + - APCI2016_WATCHDOG_ENABLEDISABLE); - /* Loading the Reload value */ - outw(data[1], - devpriv->i_IobaseAddon + - APCI2016_WATCHDOG_RELOAD_VALUE); - data[1] = data[1] >> 16; - outw(data[1], - devpriv->i_IobaseAddon + - APCI2016_WATCHDOG_RELOAD_VALUE + 2); - } else { - printk("\nThe input parameters are wrong\n"); - } - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2016_StartStopWriteWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure | -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2016_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - switch (data[0]) { - case 0: /* stop the watchdog */ - outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE); /* disable the watchdog */ - break; - case 1: /* start the watchdog */ - outw(0x0001, - devpriv->i_IobaseAddon + - APCI2016_WATCHDOG_ENABLEDISABLE); - break; - case 2: /* Software trigger */ - outw(0x0201, - devpriv->i_IobaseAddon + - APCI2016_WATCHDOG_ENABLEDISABLE); - break; - default: - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* switch(data[0]) */ - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2016_ReadWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure | -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2016_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - udelay(5); - data[0] = inw(devpriv->i_IobaseAddon + APCI2016_WATCHDOG_STATUS) & 0x1; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2016_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2016_Reset(struct comedi_device *dev) -{ - outw(0x0, devpriv->iobase + APCI2016_DIGITAL_OP); /* Resets the digital output channels */ - outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_ENABLEDISABLE); - outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE); - outw(0x0, devpriv->i_IobaseAddon + APCI2016_WATCHDOG_RELOAD_VALUE + 2); - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h deleted file mode 100644 index c42612af0fa..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2016.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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. - */ -/********* Definitions for APCI-2016 card *****/ - -#define APCI2016_BOARD_VENDOR_ID 0x15B8 -#define APCI2016_ADDRESS_RANGE 8 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI2016_DIGITAL_OP 0x04 -#define APCI2016_DIGITAL_OP_RW 4 - -/* ADDIDATA Enable Disable */ - -#define ADDIDATA_ENABLE 1 -#define ADDIDATA_DISABLE 0 - -/* TIMER COUNTER WATCHDOG DEFINES */ - -#define ADDIDATA_WATCHDOG 2 -#define APCI2016_DIGITAL_OP_WATCHDOG 0 -#define APCI2016_WATCHDOG_ENABLEDISABLE 12 -#define APCI2016_WATCHDOG_RELOAD_VALUE 4 -#define APCI2016_WATCHDOG_STATUS 16 - -/* Hardware Layer functions for Apci2016 */ - -/* DO */ -int i_APCI2016_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI2016_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI2016_BitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* -* TIMER -* timer value is passed as u seconds -*/ - -int i_APCI2016_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI2016_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -int i_APCI2016_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* Interrupt functions..... */ - -/* void v_APCI2016_Interrupt(int irq, void *d); */ - -/* void v_APCI2016_Interrupt(int irq, void *d); */ -/* RESET */ -int i_APCI2016_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c deleted file mode 100644 index 002297dfe33..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.c +++ /dev/null @@ -1,579 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-2032 | Compiler : GCC | - | Module name : hwdrv_apci2032.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-2032 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ - -#include "hwdrv_apci2032.h" -static unsigned int ui_InterruptData, ui_Type; -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2032_ConfigDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[1] : 1 Enable VCC Interrupt | -| 0 Disable VCC Interrupt | -| data[2] : 1 Enable CC Interrupt | -| 0 Disable CC Interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2032_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ul_Command = 0; - devpriv->tsk_Current = current; - - if ((data[0] != 0) && (data[0] != 1)) { - comedi_error(dev, - "Not a valid Data !!! ,Data should be 1 or 0\n"); - return -EINVAL; - } /* if ( (data[0]!=0) && (data[0]!=1) ) */ - if (data[0]) { - devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } /* if (data[0]) */ - else { - devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } /* else if (data[0]) */ - - if (data[1] == ADDIDATA_ENABLE) { - ul_Command = ul_Command | 0x1; - } /* if (data[1] == ADDIDATA_ENABLE) */ - else { - ul_Command = ul_Command & 0xFFFFFFFE; - } /* elseif (data[1] == ADDIDATA_ENABLE) */ - if (data[2] == ADDIDATA_ENABLE) { - ul_Command = ul_Command | 0x2; - } /* if (data[2] == ADDIDATA_ENABLE) */ - else { - ul_Command = ul_Command & 0xFFFFFFFD; - } /* elseif (data[2] == ADDIDATA_ENABLE) */ - outl(ul_Command, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); - ui_InterruptData = inl(devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2032_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To Write | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2032_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp, ui_Temp1; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - if (devpriv->b_OutputMemoryStatus) { - ui_Temp = inl(devpriv->iobase + APCI2032_DIGITAL_OP); - - } /* if(devpriv->b_OutputMemoryStatus ) */ - else { - ui_Temp = 0; - } /* if(devpriv->b_OutputMemoryStatus ) */ - if (data[3] == 0) { - if (data[1] == 0) { - data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; - outl(data[0], devpriv->iobase + APCI2032_DIGITAL_OP); - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = - (data[0] << (2 * - data[2])) | ui_Temp; - break; - - case 4: - data[0] = - (data[0] << (4 * - data[2])) | ui_Temp; - break; - - case 8: - data[0] = - (data[0] << (8 * - data[2])) | ui_Temp; - break; - - case 16: - data[0] = - (data[0] << (16 * - data[2])) | ui_Temp; - break; - case 31: - data[0] = data[0] | ui_Temp; - break; - - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - - outl(data[0], - devpriv->iobase + APCI2032_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==0) */ - else { - if (data[3] == 1) { - if (data[1] == 0) { - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - (data[0] << ui_NoOfChannel) ^ - 0xffffffff; - data[0] = data[0] & ui_Temp; - outl(data[0], - devpriv->iobase + APCI2032_DIGITAL_OP); - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = ~data[0] & 0x3; - ui_Temp1 = 3; - ui_Temp1 = - ui_Temp1 << 2 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (2 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - - case 4: - data[0] = ~data[0] & 0xf; - ui_Temp1 = 15; - ui_Temp1 = - ui_Temp1 << 4 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (4 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - - case 8: - data[0] = ~data[0] & 0xff; - ui_Temp1 = 255; - ui_Temp1 = - ui_Temp1 << 8 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (8 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - - case 16: - data[0] = ~data[0] & 0xffff; - ui_Temp1 = 65535; - ui_Temp1 = - ui_Temp1 << 16 * - data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (16 * - data - [2])) ^ - 0xffffffff) & ui_Temp; - break; - - case 31: - break; - default: - comedi_error(dev, - " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - - outl(data[0], - devpriv->iobase + - APCI2032_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==1); */ - else { - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* if else data[3]==1) */ - } /* if else data[3]==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2032_ReadDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel or port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2032_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp; - unsigned int ui_NoOfChannel; - ui_NoOfChannel = CR_CHAN(insn->chanspec); - ui_Temp = data[0]; - *data = inl(devpriv->iobase + APCI2032_DIGITAL_OP_RW); - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if (ui_Temp==0) */ - else { - if (ui_Temp == 1) { - switch (ui_NoOfChannel) { - - case 2: - *data = (*data >> (2 * data[1])) & 3; - break; - - case 4: - *data = (*data >> (4 * data[1])) & 15; - break; - - case 8: - *data = (*data >> (8 * data[1])) & 255; - break; - - case 16: - *data = (*data >> (16 * data[1])) & 65535; - break; - - case 31: - break; - - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - } /* if (ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* elseif (ui_Temp==1) */ - } - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2032_ConfigWatchdog(comedi_device -| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data)| -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2032_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (data[0] == 0) { - /* Disable the watchdog */ - outl(0x0, - devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + - APCI2032_TCW_PROG); - /* Loading the Reload value */ - outl(data[1], - devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + - APCI2032_TCW_RELOAD_VALUE); - } else { - printk("\nThe input parameters are wrong\n"); - return -EINVAL; - } - - return insn->n; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI2032_StartStopWriteWatchdog | - | (struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data); | - +----------------------------------------------------------------------------+ - | Task : Start / Stop The Watchdog | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ - */ - -int i_APCI2032_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - switch (data[0]) { - case 0: /* stop the watchdog */ - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); /* disable the watchdog */ - break; - case 1: /* start the watchdog */ - outl(0x0001, - devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + - APCI2032_TCW_PROG); - break; - case 2: /* Software trigger */ - outl(0x0201, - devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + - APCI2032_TCW_PROG); - break; - default: - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2032_ReadWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2032_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - data[0] = - inl(devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + - APCI2032_TCW_TRIG_STATUS) & 0x1; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : void v_APCI2032_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -void v_APCI2032_Interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - unsigned int ui_DO; - - ui_DO = inl(devpriv->iobase + APCI2032_DIGITAL_OP_IRQ) & 0x1; /* Check if VCC OR CC interrupt has occurred. */ - - if (ui_DO == 0) { - printk("\nInterrupt from unKnown source\n"); - } /* if(ui_DO==0) */ - if (ui_DO) { - /* Check for Digital Output interrupt Type - 1: Vcc interrupt 2: CC interrupt. */ - ui_Type = - inl(devpriv->iobase + - APCI2032_DIGITAL_OP_INTERRUPT_STATUS) & 0x3; - outl(0x0, - devpriv->iobase + APCI2032_DIGITAL_OP + - APCI2032_DIGITAL_OP_INTERRUPT); - if (ui_Type == 1) { - /* Sends signal to user space */ - send_sig(SIGIO, devpriv->tsk_Current, 0); - } /* if (ui_Type==1) */ - else { - if (ui_Type == 2) { - /* Sends signal to user space */ - send_sig(SIGIO, devpriv->tsk_Current, 0); - } /* if (ui_Type==2) */ - } /* else if (ui_Type==1) */ - } /* if(ui_DO) */ - - return; - -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2032_ReadInterruptStatus | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task :Reads the interrupt status register | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2032_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - *data = ui_Type; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2032_Reset(struct comedi_device *dev) | -| | -+----------------------------------------------------------------------------+ -| Task :Resets the registers of the card | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2032_Reset(struct comedi_device *dev) -{ - devpriv->b_DigitalOutputRegister = 0; - ui_Type = 0; - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP); /* Resets the output channels */ - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_INTERRUPT); /* Disables the interrupt. */ - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_PROG); /* disable the watchdog */ - outl(0x0, devpriv->iobase + APCI2032_DIGITAL_OP_WATCHDOG + APCI2032_TCW_RELOAD_VALUE); /* reload=0 */ - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h deleted file mode 100644 index ab145e7c940..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2032.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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. - */ - -/********* Definitions for APCI-2032 card *****/ - -/* Card Specific information */ -#define APCI2032_BOARD_VENDOR_ID 0x15B8 -#define APCI2032_ADDRESS_RANGE 63 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI2032_DIGITAL_OP 0 -#define APCI2032_DIGITAL_OP_RW 0 -#define APCI2032_DIGITAL_OP_INTERRUPT 4 -#define APCI2032_DIGITAL_OP_IRQ 12 - -/* Digital Output Interrupt Status */ -#define APCI2032_DIGITAL_OP_INTERRUPT_STATUS 8 - -/* Digital Output Interrupt Enable Disable. */ -#define APCI2032_DIGITAL_OP_VCC_INTERRUPT_ENABLE 0x1 -#define APCI2032_DIGITAL_OP_VCC_INTERRUPT_DISABLE 0xFFFFFFFE -#define APCI2032_DIGITAL_OP_CC_INTERRUPT_ENABLE 0x2 -#define APCI2032_DIGITAL_OP_CC_INTERRUPT_DISABLE 0xFFFFFFFD - -/* ADDIDATA Enable Disable */ - -#define ADDIDATA_ENABLE 1 -#define ADDIDATA_DISABLE 0 - -/* TIMER COUNTER WATCHDOG DEFINES */ - -#define ADDIDATA_WATCHDOG 2 -#define APCI2032_DIGITAL_OP_WATCHDOG 16 -#define APCI2032_TCW_RELOAD_VALUE 4 -#define APCI2032_TCW_TIMEBASE 8 -#define APCI2032_TCW_PROG 12 -#define APCI2032_TCW_TRIG_STATUS 16 -#define APCI2032_TCW_IRQ 20 - -/* Hardware Layer functions for Apci2032 */ - -/* DO */ -int i_APCI2032_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2032_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2032_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2032_ReadInterruptStatus(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* TIMER - * timer value is passed as u seconds -*/ - -int i_APCI2032_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2032_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2032_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* Interrupt functions..... */ - -void v_APCI2032_Interrupt(int irq, void *d); - -/* Reset functions */ -int i_APCI2032_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c deleted file mode 100644 index 3d378b5ecbc..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.c +++ /dev/null @@ -1,549 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-2200 | Compiler : GCC | - | Module name : hwdrv_apci2200.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-2200 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ -#include "hwdrv_apci2200.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_Read1DigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the digital input | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2200_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_TmpValue = 0; - unsigned int ui_Channel; - ui_Channel = CR_CHAN(insn->chanspec); - if (ui_Channel <= 7) { - ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI2200_DIGITAL_IP); - *data = (ui_TmpValue >> ui_Channel) & 0x1; - } /* if(ui_Channel >= 0 && ui_Channel <=7) */ - else { - printk("\nThe specified channel does not exist\n"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* else if(ui_Channel >= 0 && ui_Channel <=7) */ - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_ReadMoreDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Return the status of the Requested digital inputs | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2200_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - unsigned int ui_PortValue = data[0]; - unsigned int ui_Mask = 0; - unsigned int ui_NoOfChannels; - - ui_NoOfChannels = CR_CHAN(insn->chanspec); - - *data = (unsigned int) inw(devpriv->iobase + APCI2200_DIGITAL_IP); - switch (ui_NoOfChannels) { - case 2: - ui_Mask = 3; - *data = (*data >> (2 * ui_PortValue)) & ui_Mask; - break; - case 4: - ui_Mask = 15; - *data = (*data >> (4 * ui_PortValue)) & ui_Mask; - break; - case 7: - break; - - default: - printk("\nWrong parameters\n"); - return -EINVAL; /* "sorry channel spec wrong " */ - break; - } /* switch(ui_NoOfChannels) */ - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_ConfigDigitalOutput (struct comedi_device *dev, -| struct comedi_subdevice *s struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| data[0] :1:Memory on | -| 0:Memory off | -| | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI2200_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - devpriv->b_OutputMemoryStatus = data[0]; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes port value To the selected port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2200_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp, ui_Temp1; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - if (devpriv->b_OutputMemoryStatus) { - ui_Temp = inw(devpriv->iobase + APCI2200_DIGITAL_OP); - - } /* if(devpriv->b_OutputMemoryStatus ) */ - else { - 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->iobase + APCI2200_DIGITAL_OP); - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = - (data[0] << (2 * - data[2])) | ui_Temp; - break; - - case 4: - data[0] = - (data[0] << (4 * - data[2])) | ui_Temp; - break; - - case 8: - data[0] = - (data[0] << (8 * - data[2])) | ui_Temp; - break; - case 15: - data[0] = data[0] | ui_Temp; - break; - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - - outw(data[0], - devpriv->iobase + APCI2200_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==0) */ - else { - if (data[3] == 1) { - if (data[1] == 0) { - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = (data[0] << ui_NoOfChannel) ^ 0xffff; - data[0] = data[0] & ui_Temp; - outw(data[0], - devpriv->iobase + APCI2200_DIGITAL_OP); - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = ~data[0] & 0x3; - ui_Temp1 = 3; - ui_Temp1 = - ui_Temp1 << 2 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (2 * - data - [2])) ^ - 0xffff) & ui_Temp; - break; - - case 4: - data[0] = ~data[0] & 0xf; - ui_Temp1 = 15; - ui_Temp1 = - ui_Temp1 << 4 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (4 * - data - [2])) ^ - 0xffff) & ui_Temp; - break; - - case 8: - data[0] = ~data[0] & 0xff; - ui_Temp1 = 255; - ui_Temp1 = - ui_Temp1 << 8 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (8 * - data - [2])) ^ - 0xffff) & ui_Temp; - break; - case 15: - break; - - default: - comedi_error(dev, - " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - - outw(data[0], - devpriv->iobase + - APCI2200_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==1); */ - else { - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* if else data[3]==1) */ - } /* if else data[3]==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_ReadDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel or port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - unsigned int ui_Temp; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - ui_Temp = data[0]; - *data = inw(devpriv->iobase + APCI2200_DIGITAL_OP); - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if(ui_Temp==0) */ - else { - if (ui_Temp == 1) { - switch (ui_NoOfChannel) { - - case 2: - *data = (*data >> (2 * data[1])) & 3; - break; - - case 4: - *data = (*data >> (4 * data[1])) & 15; - break; - - case 8: - *data = (*data >> (8 * data[1])) & 255; - break; - - case 15: - break; - - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - } /* if(ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* elseif(ui_Temp==1) */ - } /* elseif(ui_Temp==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, -| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Configures The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (data[0] == 0) { - /* Disable the watchdog */ - outw(0x0, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_ENABLEDISABLE); - /* Loading the Reload value */ - outw(data[1], - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_RELOAD_VALUE); - data[1] = data[1] >> 16; - outw(data[1], - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_RELOAD_VALUE + 2); - } /* if(data[0]==0) */ - else { - printk("\nThe input parameters are wrong\n"); - return -EINVAL; - } /* elseif(data[0]==0) */ - - return insn->n; -} - - /* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI2200_StartStopWriteWatchdog | - | (struct comedi_device *dev,struct comedi_subdevice *s, - struct comedi_insn *insn,unsigned int *data); | - +----------------------------------------------------------------------------+ - | Task : Start / Stop The Watchdog | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | struct comedi_subdevice *s, :pointer to subdevice structure - struct comedi_insn *insn :pointer to insn structure | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ - */ - -int i_APCI2200_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - switch (data[0]) { - case 0: /* stop the watchdog */ - outw(0x0, devpriv->iobase + APCI2200_WATCHDOG + APCI2200_WATCHDOG_ENABLEDISABLE); /* disable the watchdog */ - break; - case 1: /* start the watchdog */ - outw(0x0001, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_ENABLEDISABLE); - break; - case 2: /* Software trigger */ - outw(0x0201, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_ENABLEDISABLE); - break; - default: - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* switch(data[0]) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_ReadWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn, -| unsigned int *data); | -+----------------------------------------------------------------------------+ -| Task : Read The Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s, :pointer to subdevice structure -| struct comedi_insn *insn :pointer to insn structure | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2200_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[0] = - inw(devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_STATUS) & 0x1; - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI2200_Reset(struct comedi_device *dev) | | -+----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI2200_Reset(struct comedi_device *dev) -{ - outw(0x0, devpriv->iobase + APCI2200_DIGITAL_OP); /* RESETS THE DIGITAL OUTPUTS */ - outw(0x0, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_ENABLEDISABLE); - outw(0x0, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_RELOAD_VALUE); - outw(0x0, - devpriv->iobase + APCI2200_WATCHDOG + - APCI2200_WATCHDOG_RELOAD_VALUE + 2); - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h deleted file mode 100644 index 83f42af84b8..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci2200.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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. - */ - -/********* Definitions for APCI-2200 card *****/ - -/* Card Specific information */ -#define APCI2200_BOARD_VENDOR_ID 0x15b8 -#define APCI2200_ADDRESS_RANGE 64 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI2200_DIGITAL_OP 4 -#define APCI2200_DIGITAL_IP 0 - -/* TIMER COUNTER WATCHDOG DEFINES */ - -#define APCI2200_WATCHDOG 0x08 -#define APCI2200_WATCHDOG_ENABLEDISABLE 12 -#define APCI2200_WATCHDOG_RELOAD_VALUE 4 -#define APCI2200_WATCHDOG_STATUS 16 - -/* Hardware Layer functions for Apci2200 */ - -/* Digital Input */ -int i_APCI2200_ReadMoreDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2200_Read1DigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* Digital Output */ -int i_APCI2200_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2200_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* TIMER */ -int i_APCI2200_ConfigWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2200_StartStopWriteWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI2200_ReadWatchdog(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* reset */ -int i_APCI2200_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index e886ced4978..764c8f17f8f 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* @@ -44,8 +40,205 @@ You should also find the complete GPL in the COPYING file accompanying this sour +----------+-----------+------------------------------------------------+ */ -#include "hwdrv_apci3120.h" -static unsigned int ui_Temp; +#include <linux/delay.h> + +/* + * ADDON RELATED ADDITIONS + */ +/* Constant */ +#define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00 +#define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200 +#define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L +#define APCI3120_AMWEN_ENABLE 0x02 +#define APCI3120_A2P_FIFO_WRITE_ENABLE 0x01 +#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 0x20000000L +#define APCI3120_ENABLE_WRITE_TC_INT 0x00004000L +#define APCI3120_CLEAR_WRITE_TC_INT 0x00040000L +#define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0 +#define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0 +#define APCI3120_DISABLE_BUS_MASTER_PCI 0x0 + +/* ADD_ON ::: this needed since apci supports 16 bit interface to add on */ +#define APCI3120_ADD_ON_AGCSTS_LOW 0x3C +#define APCI3120_ADD_ON_AGCSTS_HIGH (APCI3120_ADD_ON_AGCSTS_LOW + 2) +#define APCI3120_ADD_ON_MWAR_LOW 0x24 +#define APCI3120_ADD_ON_MWAR_HIGH (APCI3120_ADD_ON_MWAR_LOW + 2) +#define APCI3120_ADD_ON_MWTC_LOW 0x058 +#define APCI3120_ADD_ON_MWTC_HIGH (APCI3120_ADD_ON_MWTC_LOW + 2) + +/* AMCC */ +#define APCI3120_AMCC_OP_MCSR 0x3C +#define APCI3120_AMCC_OP_REG_INTCSR 0x38 + +/* for transfer count enable bit */ +#define AGCSTS_TC_ENABLE 0x10000000 + +/* used for test on mixture of BIP/UNI ranges */ +#define APCI3120_BIPOLAR_RANGES 4 + +#define APCI3120_ADDRESS_RANGE 16 + +#define APCI3120_DISABLE 0 +#define APCI3120_ENABLE 1 + +#define APCI3120_START 1 +#define APCI3120_STOP 0 + +#define APCI3120_EOC_MODE 1 +#define APCI3120_EOS_MODE 2 +#define APCI3120_DMA_MODE 3 + +/* DIGITAL INPUT-OUTPUT DEFINE */ + +#define APCI3120_DIGITAL_OUTPUT 0x0d +#define APCI3120_RD_STATUS 0x02 +#define APCI3120_RD_FIFO 0x00 + +/* digital output insn_write ON /OFF selection */ +#define APCI3120_SET4DIGITALOUTPUTON 1 +#define APCI3120_SET4DIGITALOUTPUTOFF 0 + +/* analog output SELECT BIT */ +#define APCI3120_ANALOG_OP_CHANNEL_1 0x0000 +#define APCI3120_ANALOG_OP_CHANNEL_2 0x4000 +#define APCI3120_ANALOG_OP_CHANNEL_3 0x8000 +#define APCI3120_ANALOG_OP_CHANNEL_4 0xc000 +#define APCI3120_ANALOG_OP_CHANNEL_5 0x0000 +#define APCI3120_ANALOG_OP_CHANNEL_6 0x4000 +#define APCI3120_ANALOG_OP_CHANNEL_7 0x8000 +#define APCI3120_ANALOG_OP_CHANNEL_8 0xc000 + +/* Enable external trigger bit in nWrAddress */ +#define APCI3120_ENABLE_EXT_TRIGGER 0x8000 + +/* ANALOG OUTPUT AND INPUT DEFINE */ +#define APCI3120_UNIPOLAR 0x80 +#define APCI3120_BIPOLAR 0x00 +#define APCI3120_ANALOG_OUTPUT_1 0x08 +#define APCI3120_ANALOG_OUTPUT_2 0x0a +#define APCI3120_1_GAIN 0x00 +#define APCI3120_2_GAIN 0x10 +#define APCI3120_5_GAIN 0x20 +#define APCI3120_10_GAIN 0x30 +#define APCI3120_SEQ_RAM_ADDRESS 0x06 +#define APCI3120_RESET_FIFO 0x0c +#define APCI3120_TIMER_0_MODE_2 0x01 +#define APCI3120_TIMER_0_MODE_4 0x2 +#define APCI3120_SELECT_TIMER_0_WORD 0x00 +#define APCI3120_ENABLE_TIMER0 0x1000 +#define APCI3120_CLEAR_PR 0xf0ff +#define APCI3120_CLEAR_PA 0xfff0 +#define APCI3120_CLEAR_PA_PR (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA) + +/* nWrMode_Select */ +#define APCI3120_ENABLE_SCAN 0x8 +#define APCI3120_DISABLE_SCAN (~APCI3120_ENABLE_SCAN) +#define APCI3120_ENABLE_EOS_INT 0x2 + +#define APCI3120_DISABLE_EOS_INT (~APCI3120_ENABLE_EOS_INT) +#define APCI3120_ENABLE_EOC_INT 0x1 +#define APCI3120_DISABLE_EOC_INT (~APCI3120_ENABLE_EOC_INT) +#define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER \ + (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT) +#define APCI3120_DISABLE_ALL_INTERRUPT \ + (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT) + +/* status register bits */ +#define APCI3120_EOC 0x8000 +#define APCI3120_EOS 0x2000 + +/* software trigger dummy register */ +#define APCI3120_START_CONVERSION 0x02 + +/* TIMER DEFINE */ +#define APCI3120_QUARTZ_A 70 +#define APCI3120_QUARTZ_B 50 +#define APCI3120_TIMER 1 +#define APCI3120_WATCHDOG 2 +#define APCI3120_TIMER_DISABLE 0 +#define APCI3120_TIMER_ENABLE 1 +#define APCI3120_ENABLE_TIMER2 0x4000 +#define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2) +#define APCI3120_ENABLE_TIMER_INT 0x04 +#define APCI3120_DISABLE_TIMER_INT (~APCI3120_ENABLE_TIMER_INT) +#define APCI3120_WRITE_MODE_SELECT 0x0e +#define APCI3120_SELECT_TIMER_0_WORD 0x00 +#define APCI3120_SELECT_TIMER_1_WORD 0x01 +#define APCI3120_TIMER_1_MODE_2 0x4 + +/* $$ BIT FOR MODE IN nCsTimerCtr1 */ +#define APCI3120_TIMER_2_MODE_0 0x0 +#define APCI3120_TIMER_2_MODE_2 0x10 +#define APCI3120_TIMER_2_MODE_5 0x30 + +/* $$ BIT FOR MODE IN nCsTimerCtr0 */ +#define APCI3120_SELECT_TIMER_2_LOW_WORD 0x02 +#define APCI3120_SELECT_TIMER_2_HIGH_WORD 0x03 + +#define APCI3120_TIMER_CRT0 0x0d +#define APCI3120_TIMER_CRT1 0x0c + +#define APCI3120_TIMER_VALUE 0x04 +#define APCI3120_TIMER_STATUS_REGISTER 0x0d +#define APCI3120_RD_STATUS 0x02 +#define APCI3120_WR_ADDRESS 0x00 +#define APCI3120_ENABLE_WATCHDOG 0x20 +#define APCI3120_DISABLE_WATCHDOG (~APCI3120_ENABLE_WATCHDOG) +#define APCI3120_ENABLE_TIMER_COUNTER 0x10 +#define APCI3120_DISABLE_TIMER_COUNTER (~APCI3120_ENABLE_TIMER_COUNTER) +#define APCI3120_FC_TIMER 0x1000 +#define APCI3120_ENABLE_TIMER0 0x1000 +#define APCI3120_ENABLE_TIMER1 0x2000 +#define APCI3120_ENABLE_TIMER2 0x4000 +#define APCI3120_DISABLE_TIMER0 (~APCI3120_ENABLE_TIMER0) +#define APCI3120_DISABLE_TIMER1 (~APCI3120_ENABLE_TIMER1) +#define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2) + +#define APCI3120_TIMER2_SELECT_EOS 0xc0 +#define APCI3120_COUNTER 3 +#define APCI3120_DISABLE_ALL_TIMER (APCI3120_DISABLE_TIMER0 & \ + APCI3120_DISABLE_TIMER1 & \ + APCI3120_DISABLE_TIMER2) + +#define MAX_ANALOGINPUT_CHANNELS 32 + +struct str_AnalogReadInformation { + /* EOC or EOS */ + unsigned char b_Type; + /* Interrupt use or not */ + unsigned char b_InterruptFlag; + /* Selection of the conversion time */ + unsigned int ui_ConvertTiming; + /* Number of channel to read */ + unsigned char b_NbrOfChannel; + /* Number of the channel to be read */ + unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS]; + /* Gain of each channel */ + unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS]; +}; + +/* ANALOG INPUT RANGE */ +static const struct comedi_lrange range_apci3120_ai = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1) + } +}; + +/* ANALOG OUTPUT RANGE */ +static const struct comedi_lrange range_apci3120_ao = { + 2, { + BIP_RANGE(10), + UNI_RANGE(10) + } +}; + /* FUNCTION DEFINITIONS */ @@ -55,28 +248,13 @@ static unsigned int ui_Temp; +----------------------------------------------------------------------------+ */ -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev,| -| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Calls card specific function | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int apci3120_ai_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + const struct addi_board *this_board = comedi_board(dev); + struct addi_private *devpriv = dev->private; unsigned int i; if ((data[0] != APCI3120_EOC_MODE) && (data[0] != APCI3120_EOS_MODE)) @@ -91,7 +269,7 @@ int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_su for (i = 0; i < data[3]; i++) { if (CR_CHAN(data[4 + i]) >= - devpriv->s_EeParameters.i_NbrAiChannel) { + this_board->i_NbrAiChannel) { printk("bad channel list\n"); return -2; } @@ -121,31 +299,72 @@ int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_su } /* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, | -| struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : card specific function | -| Reads analog input in synchronous mode | -| EOC and EOS is selected as per configured | -| if no conversion time is set uses default conversion | -| time 10 microsec. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ + * This function will first check channel list is ok or not and then + * initialize the sequence RAM with the polarity, Gain,Channel number. + * If the last argument of function "check"is 1 then it only checks + * the channel list is ok or not. + */ +static int apci3120_setup_chan_list(struct comedi_device *dev, + struct comedi_subdevice *s, + int n_chan, + unsigned int *chanlist, + char check) +{ + struct addi_private *devpriv = dev->private; + unsigned int i; /* , differencial=0, bipolar=0; */ + unsigned int gain; + unsigned short us_TmpValue; + + /* correct channel and range number check itself comedi/range.c */ + if (n_chan < 1) { + if (!check) + comedi_error(dev, "range/channel list is empty!"); + return 0; + } + /* All is ok, so we can setup channel/range list */ + if (check) + return 1; + + /* 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; + outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); + + for (i = 0; i < n_chan; i++) { + /* store range list to card */ + 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...... */ -int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + 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.... */ + outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); + + printk("\n Gain = %i", + (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2)); + printk("\n Channel = %i", CR_CHAN(chanlist[i])); + printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR); + } + return 1; /* we can serve this with scan logic */ +} + +/* + * Reads analog input in synchronous mode EOC and EOS is selected + * as per configured if no conversion time is set uses default + * conversion time 10 microsec. + */ +static int apci3120_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + const struct addi_board *this_board = comedi_board(dev); + struct addi_private *devpriv = dev->private; unsigned short us_ConvertTiming, us_TmpValue, i; unsigned char b_Tmp; @@ -156,7 +375,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd } else us_ConvertTiming = (unsigned short) (devpriv->ui_EocEosConversionTime / 1000); /* nano to useconds */ - /* this_board->i_hwdrv_InsnReadAnalogInput(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */ + /* this_board->ai_read(dev,us_ConvertTiming,insn->n,&insn->chanspec,data,insn->unused[0]); */ /* Clear software registers */ devpriv->b_TimerSelectMode = 0; @@ -198,10 +417,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd inw(devpriv->iobase + APCI3120_RESET_FIFO); /* Initialize the sequence array */ - - /* if (!i_APCI3120_SetupChannelList(dev,s,1,chanlist,0)) return -EINVAL; */ - - if (!i_APCI3120_SetupChannelList(dev, s, 1, + if (!apci3120_setup_chan_list(dev, s, 1, &insn->chanspec, 0)) return -EINVAL; @@ -293,7 +509,7 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd outw(devpriv->us_OutputRegister, devpriv->iobase + APCI3120_WR_ADDRESS); - if (!i_APCI3120_SetupChannelList(dev, s, + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, devpriv->ui_AiChannelList, 0)) return -EINVAL; @@ -387,26 +603,85 @@ int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subd } +static int apci3120_reset(struct comedi_device *dev) +{ + struct addi_private *devpriv = dev->private; + unsigned int i; + unsigned short us_TmpValue; + + devpriv->ai_running = 0; + devpriv->b_EocEosInterrupt = APCI3120_DISABLE; + devpriv->b_InterruptMode = APCI3120_EOC_MODE; + devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */ + + /* variables used in timer subdevice */ + devpriv->b_Timer2Mode = 0; + devpriv->b_Timer2Interrupt = 0; + devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */ + + /* Disable all interrupts, watchdog for the anolog output */ + devpriv->b_ModeSelectRegister = 0; + outb(devpriv->b_ModeSelectRegister, + dev->iobase + APCI3120_WRITE_MODE_SELECT); + + /* Disables all counters, ext trigger and clears PA, PR */ + devpriv->us_OutputRegister = 0; + outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); + /* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev,| -| struct comedi_subdevice *s)| -| | -+----------------------------------------------------------------------------+ -| Task : Stops Cyclic acquisition | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| | -+----------------------------------------------------------------------------+ -| Return Value :0 | -| | -+----------------------------------------------------------------------------+ -*/ + * 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 */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */ + + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */ + outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */ + 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 */ + inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */ + inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */ + + /* code to reset the RAM sequence */ + for (i = 0; i < 16; i++) { + us_TmpValue = i << 8; /* select the location */ + outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); + } + return 0; +} + +static int apci3120_exttrig_enable(struct comedi_device *dev) +{ + struct addi_private *devpriv = dev->private; + + devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER; + outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); + return 0; +} + +static int apci3120_exttrig_disable(struct comedi_device *dev) +{ + struct addi_private *devpriv = dev->private; + + devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER; + outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); + return 0; +} -int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s) +static int apci3120_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { + struct addi_private *devpriv = dev->private; + /* Disable A2P Fifo write and AMWEN signal */ outw(0, devpriv->i_IobaseAddon + 4); @@ -426,7 +701,7 @@ int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_su * devpriv->i_IobaseAmcc+AMCC_OP_REG_MCSR); stop DMA */ /* Disable ext trigger */ - i_APCI3120_ExttrigDisable(dev); + apci3120_exttrig_disable(dev); devpriv->us_OutputRegister = 0; /* stop counters */ @@ -443,169 +718,77 @@ int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_su inb(dev->iobase + APCI3120_RESET_FIFO); inw(dev->iobase + APCI3120_RD_STATUS); devpriv->ui_AiActualScan = 0; - devpriv->ui_AiActualScanPosition = 0; s->async->cur_chan = 0; - devpriv->ui_AiBufferPtr = 0; - devpriv->b_AiContinuous = 0; devpriv->ui_DmaActualBuffer = 0; - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; + devpriv->ai_running = 0; devpriv->b_InterruptMode = APCI3120_EOC_MODE; devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - i_APCI3120_Reset(dev); + apci3120_reset(dev); return 0; } -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev| -| ,struct comedi_subdevice *s,struct comedi_cmd *cmd) | -| | -+----------------------------------------------------------------------------+ -| Task : Test validity for a command for cyclic anlog input | -| acquisition | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_cmd *cmd | -+----------------------------------------------------------------------------+ -| Return Value :0 | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3120_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; - int tmp; /* divisor1,divisor2; */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + 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 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; + 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->stop_src); - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - - if (cmd->convert_src != TRIG_TIMER) - err++; - - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } - - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->scan_begin_src == TRIG_TIMER) { /* Test Delay timing */ - if (cmd->scan_begin_arg < - devpriv->s_EeParameters.ui_MinDelaytimeNs) { - cmd->scan_begin_arg = - devpriv->s_EeParameters.ui_MinDelaytimeNs; - err++; - } - } - - if (cmd->convert_src == TRIG_TIMER) { /* Test Acquisition timing */ - if (cmd->scan_begin_src == TRIG_TIMER) { - if ((cmd->convert_arg) - && (cmd->convert_arg < - devpriv->s_EeParameters. - ui_MinAcquisitiontimeNs)) { - cmd->convert_arg = devpriv->s_EeParameters. - ui_MinAcquisitiontimeNs; - err++; - } - } else { - if (cmd->convert_arg < - devpriv->s_EeParameters.ui_MinAcquisitiontimeNs - ) { - cmd->convert_arg = devpriv->s_EeParameters. - ui_MinAcquisitiontimeNs; - err++; + if (cmd->scan_begin_src == TRIG_TIMER) /* Test Delay timing */ + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000); - } - } + if (cmd->scan_begin_src == TRIG_TIMER) { + if (cmd->convert_arg) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + 10000); + } else { + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); } - if (!cmd->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } - if (cmd->chanlist_len > this_board->i_AiChannelList) { - cmd->chanlist_len = this_board->i_AiChannelList; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; /* step 4: fix up any arguments */ - if (cmd->convert_src == TRIG_TIMER) { - - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } + if (cmd->scan_begin_src == TRIG_TIMER && + cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) { + cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg; + err |= -EINVAL; } if (err) @@ -615,110 +798,24 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s } /* -+----------------------------------------------------------------------------+ -| Function name : int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, | -| struct comedi_subdevice *s) | -| | -+----------------------------------------------------------------------------+ -| Task : Does asynchronous acquisition | -| Determines the mode 1 or 2. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s) + * This is used for analog input cyclic acquisition. + * Performs the command operations. + * If DMA is configured does DMA initialization otherwise does the + * acquisition with EOS interrupt. + */ +static int apci3120_cyclic_ai(int mode, + struct comedi_device *dev, + struct comedi_subdevice *s) { + const struct addi_board *this_board = comedi_board(dev); + struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - - /* loading private structure with cmd structure inputs */ - devpriv->ui_AiFlags = cmd->flags; - devpriv->ui_AiNbrofChannels = cmd->chanlist_len; - devpriv->ui_AiScanLength = cmd->scan_end_arg; - devpriv->pui_AiChannelList = cmd->chanlist; - - /* UPDATE-0.7.57->0.7.68devpriv->AiData=s->async->data; */ - devpriv->AiData = s->async->prealloc_buf; - /* UPDATE-0.7.57->0.7.68devpriv->ui_AiDataLength=s->async->data_len; */ - devpriv->ui_AiDataLength = s->async->prealloc_bufsz; - - if (cmd->stop_src == TRIG_COUNT) - devpriv->ui_AiNbrofScans = cmd->stop_arg; - else - devpriv->ui_AiNbrofScans = 0; - - devpriv->ui_AiTimer0 = 0; /* variables changed to timer0,timer1 */ - devpriv->ui_AiTimer1 = 0; - if ((devpriv->ui_AiNbrofScans == 0) || (devpriv->ui_AiNbrofScans == -1)) - devpriv->b_AiContinuous = 1; /* user want neverending analog acquisition */ - /* stopped using cancel */ - - if (cmd->start_src == TRIG_EXT) - devpriv->b_ExttrigEnable = APCI3120_ENABLE; - else - devpriv->b_ExttrigEnable = APCI3120_DISABLE; - - if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* mode 1 or 3 */ - if (cmd->convert_src == TRIG_TIMER) { - /* mode 1 */ - - devpriv->ui_AiTimer0 = cmd->convert_arg; /* timer constant in nano seconds */ - /* return this_board->i_hwdrv_CommandAnalogInput(1,dev,s); */ - return i_APCI3120_CyclicAnalogInput(1, dev, s); - } - - } - if ((cmd->scan_begin_src == TRIG_TIMER) - && (cmd->convert_src == TRIG_TIMER)) { - /* mode 2 */ - devpriv->ui_AiTimer1 = cmd->scan_begin_arg; - devpriv->ui_AiTimer0 = cmd->convert_arg; /* variable changed timer2 to timer0 */ - /* return this_board->i_hwdrv_CommandAnalogInput(2,dev,s); */ - return i_APCI3120_CyclicAnalogInput(2, dev, s); - } - return -1; -} - -/* -+----------------------------------------------------------------------------+ -| Function name : int i_APCI3120_CyclicAnalogInput(int mode, | -| struct comedi_device * dev,struct comedi_subdevice * s) | -+----------------------------------------------------------------------------+ -| Task : This is used for analog input cyclic acquisition | -| Performs the command operations. | -| If DMA is configured does DMA initialization | -| otherwise does the acquisition with EOS interrupt. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) -{ unsigned char b_Tmp; unsigned int ui_Tmp, ui_DelayTiming = 0, ui_TimerValue1 = 0, dmalen0 = 0, dmalen1 = 0, ui_TimerValue2 = 0, ui_TimerValue0, ui_ConvertTiming; unsigned short us_TmpValue; - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - /* devpriv->b_AiCyclicAcquisition=APCI3120_ENABLE; */ - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - /*******************/ /* Resets the FIFO */ /*******************/ @@ -728,12 +825,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, /* inw(dev->iobase+APCI3120_RD_STATUS); */ /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ - /***************************/ - /* Acquisition initialized */ - /***************************/ - /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ - devpriv->b_AiCyclicAcquisition = APCI3120_ENABLE; - /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ + devpriv->ai_running = 1; /* clear software registers */ devpriv->b_TimerSelectMode = 0; @@ -776,23 +868,21 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ devpriv->ui_AiActualScan = 0; - devpriv->ui_AiActualScanPosition = 0; s->async->cur_chan = 0; - devpriv->ui_AiBufferPtr = 0; devpriv->ui_DmaActualBuffer = 0; /* value for timer2 minus -2 has to be done .....dunno y?? */ - ui_TimerValue2 = devpriv->ui_AiNbrofScans - 2; - ui_ConvertTiming = devpriv->ui_AiTimer0; + ui_TimerValue2 = cmd->stop_arg - 2; + ui_ConvertTiming = cmd->convert_arg; if (mode == 2) - ui_DelayTiming = devpriv->ui_AiTimer1; + ui_DelayTiming = cmd->scan_begin_arg; /**********************************/ /* Initializes the sequence array */ /**********************************/ - if (!i_APCI3120_SetupChannelList(dev, s, devpriv->ui_AiNbrofChannels, - devpriv->pui_AiChannelList, 0)) + if (!apci3120_setup_chan_list(dev, s, devpriv->ui_AiNbrofChannels, + cmd->chanlist, 0)) return -EINVAL; us_TmpValue = (unsigned short) inw(dev->iobase + APCI3120_RD_STATUS); @@ -844,7 +934,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, /*** EL241003 End ******************************************************************************/ if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) - i_APCI3120_ExttrigEnable(dev); /* activate EXT trigger */ + apci3120_exttrig_enable(dev); /* activate EXT trigger */ switch (mode) { case 1: /* init timer0 in mode 2 */ @@ -929,7 +1019,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, outb(devpriv->b_ModeSelectRegister, dev->iobase + APCI3120_WRITE_MODE_SELECT); - if (!devpriv->b_AiContinuous) { + if (cmd->stop_src == TRIG_COUNT) { /* * configure Timer2 For counting EOS Reset gate 2 of Timer 2 to * disable it (Set Bit D14 to 0) @@ -997,6 +1087,7 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, } } else { /* If DMA Enabled */ + unsigned int scan_bytes = cmd->scan_end_arg * sizeof(short); /* BEGIN JK 07.05.04: Comparison between WIN32 and Linux driver */ /* inw(dev->iobase+0); reset EOC bit */ @@ -1015,37 +1106,38 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, dmalen0 = devpriv->ui_DmaBufferSize[0]; dmalen1 = devpriv->ui_DmaBufferSize[1]; - if (!devpriv->b_AiContinuous) { - - if (dmalen0 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2)) { /* must we fill full first buffer? */ - dmalen0 = - devpriv->ui_AiNbrofScans * - devpriv->ui_AiScanLength * 2; - } else if (dmalen1 > (devpriv->ui_AiNbrofScans * devpriv->ui_AiScanLength * 2 - dmalen0)) /* and must we fill full second buffer when first is once filled? */ - dmalen1 = - devpriv->ui_AiNbrofScans * - devpriv->ui_AiScanLength * 2 - dmalen0; + if (cmd->stop_src == TRIG_COUNT) { + /* + * Must we fill full first buffer? And must we fill + * full second buffer when first is once filled? + */ + if (dmalen0 > (cmd->stop_arg * scan_bytes)) { + dmalen0 = cmd->stop_arg * scan_bytes; + } else if (dmalen1 > (cmd->stop_arg * scan_bytes - + dmalen0)) + dmalen1 = cmd->stop_arg * scan_bytes - + dmalen0; } - if (devpriv->ui_AiFlags & TRIG_WAKE_EOS) { + if (cmd->flags & TRIG_WAKE_EOS) { /* don't we want wake up every scan? */ - if (dmalen0 > (devpriv->ui_AiScanLength * 2)) { - dmalen0 = devpriv->ui_AiScanLength * 2; - if (devpriv->ui_AiScanLength & 1) + if (dmalen0 > scan_bytes) { + dmalen0 = scan_bytes; + if (cmd->scan_end_arg & 1) dmalen0 += 2; } - if (dmalen1 > (devpriv->ui_AiScanLength * 2)) { - dmalen1 = devpriv->ui_AiScanLength * 2; - if (devpriv->ui_AiScanLength & 1) + if (dmalen1 > scan_bytes) { + dmalen1 = scan_bytes; + if (cmd->scan_end_arg & 1) dmalen1 -= 2; if (dmalen1 < 4) dmalen1 = 4; } } else { /* isn't output buff smaller that our DMA buff? */ - if (dmalen0 > (devpriv->ui_AiDataLength)) - dmalen0 = devpriv->ui_AiDataLength; - if (dmalen1 > (devpriv->ui_AiDataLength)) - dmalen1 = devpriv->ui_AiDataLength; + if (dmalen0 > s->async->prealloc_bufsz) + dmalen0 = s->async->prealloc_bufsz; + if (dmalen1 > s->async->prealloc_bufsz) + dmalen1 = s->async->prealloc_bufsz; } devpriv->ui_DmaBufferUsesize[0] = dmalen0; devpriv->ui_DmaBufferUsesize[1] = dmalen1; @@ -1183,8 +1275,8 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, /* END JK 07.05.04: Comparison between WIN32 and Linux driver */ } - if ((devpriv->us_UseDma == APCI3120_DISABLE) - && !devpriv->b_AiContinuous) { + if (devpriv->us_UseDma == APCI3120_DISABLE && + cmd->stop_src == TRIG_COUNT) { /* set gate 2 to start conversion */ devpriv->us_OutputRegister = devpriv->us_OutputRegister | APCI3120_ENABLE_TIMER2; @@ -1217,241 +1309,239 @@ int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, } /* -+----------------------------------------------------------------------------+ -| intERNAL FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ + * Does asynchronous acquisition. + * Determines the mode 1 or 2. + */ +static int apci3120_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct addi_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; -/* -+----------------------------------------------------------------------------+ -| Function name : int i_APCI3120_Reset(struct comedi_device *dev) | -| | -| | -+----------------------------------------------------------------------------+ -| Task : Hardware reset function | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ + /* loading private structure with cmd structure inputs */ + devpriv->ui_AiNbrofChannels = cmd->chanlist_len; -int i_APCI3120_Reset(struct comedi_device *dev) -{ - unsigned int i; - unsigned short us_TmpValue; + if (cmd->start_src == TRIG_EXT) + devpriv->b_ExttrigEnable = APCI3120_ENABLE; + else + devpriv->b_ExttrigEnable = APCI3120_DISABLE; - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; - devpriv->b_EocEosInterrupt = APCI3120_DISABLE; - devpriv->b_InterruptMode = APCI3120_EOC_MODE; - devpriv->ui_EocEosConversionTime = 0; /* set eoc eos conv time to 0 */ - devpriv->b_OutputMemoryStatus = 0; + if (cmd->scan_begin_src == TRIG_FOLLOW) + return apci3120_cyclic_ai(1, dev, s); + else /* TRIG_TIMER */ + return apci3120_cyclic_ai(2, dev, s); +} - /* variables used in timer subdevice */ - devpriv->b_Timer2Mode = 0; - devpriv->b_Timer2Interrupt = 0; - devpriv->b_ExttrigEnable = 0; /* Disable ext trigger */ +/* + * This function copies the data from DMA buffer to the Comedi buffer. + */ +static void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned short *dma_buffer, + unsigned int num_samples) +{ + struct addi_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - /* Disable all interrupts, watchdog for the anolog output */ - devpriv->b_ModeSelectRegister = 0; - outb(devpriv->b_ModeSelectRegister, - dev->iobase + APCI3120_WRITE_MODE_SELECT); + devpriv->ui_AiActualScan += + (s->async->cur_chan + num_samples) / cmd->scan_end_arg; + s->async->cur_chan += num_samples; + s->async->cur_chan %= cmd->scan_end_arg; - /* Disables all counters, ext trigger and clears PA, PR */ - devpriv->us_OutputRegister = 0; - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); + cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); +} /* - * Code to set the all anolog o/p channel to 0v 8191 is decimal - * value for zero(0 v)volt in bipolar mode(default) + * This is a handler for the DMA interrupt. + * This function copies the data to Comedi Buffer. + * For continuous DMA it reinitializes the DMA operation. + * For single mode DMA it stop the acquisition. */ - 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 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_4, dev->iobase + APCI3120_ANALOG_OUTPUT_1); /* channel 4 */ +static void apci3120_interrupt_dma(int irq, void *d) +{ + struct comedi_device *dev = d; + struct addi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int next_dma_buf, samplesinbuf; + unsigned long low_word, high_word, var; + unsigned int ui_Tmp; - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_5, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 5 */ - outw(8191 | APCI3120_ANALOG_OP_CHANNEL_6, dev->iobase + APCI3120_ANALOG_OUTPUT_2); /* channel 6 */ - 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 */ + samplesinbuf = + devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] - + inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC); - /* Reset digital output to L0W */ + if (samplesinbuf < + devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) { + comedi_error(dev, "Interrupted DMA transfer!"); + } + if (samplesinbuf & 1) { + comedi_error(dev, "Odd count of bytes in DMA ring!"); + apci3120_cancel(dev, s); + return; + } + samplesinbuf = samplesinbuf >> 1; /* number of received samples */ + if (devpriv->b_DmaDoubleBuffer) { + /* switch DMA buffers if is used double buffering */ + next_dma_buf = 1 - devpriv->ui_DmaActualBuffer; -/* ES05 outb(0x0,dev->iobase+APCI3120_DIGITAL_OUTPUT); */ - udelay(10); + ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; + outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); - inw(dev->iobase + 0); /* make a dummy read */ - inb(dev->iobase + APCI3120_RESET_FIFO); /* flush FIFO */ - inw(dev->iobase + APCI3120_RD_STATUS); /* flush A/D status register */ + /* changed since 16 bit interface for add on */ + outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); + 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); /* 0x1000 is out putted in windows driver */ - /* code to reset the RAM sequence */ - for (i = 0; i < 16; i++) { - us_TmpValue = i << 8; /* select the location */ - outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); - } - return 0; -} + var = devpriv->ul_DmaBufferHw[next_dma_buf]; + low_word = var & 0xffff; + var = devpriv->ul_DmaBufferHw[next_dma_buf]; + high_word = var / 65536; + + /* DMA Start Address Low */ + outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); + outw(low_word, devpriv->i_IobaseAddon + 2); + + /* DMA Start Address High */ + outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); + outw(high_word, devpriv->i_IobaseAddon + 2); + + var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; + low_word = var & 0xffff; + var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; + high_word = var / 65536; + + /* Nbr of acquisition LOW */ + outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); + outw(low_word, devpriv->i_IobaseAddon + 2); + + /* Nbr of acquisition HIGH */ + outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); + outw(high_word, devpriv->i_IobaseAddon + 2); /* -+----------------------------------------------------------------------------+ -| Function name : int i_APCI3120_SetupChannelList(struct comedi_device * dev, | -| struct comedi_subdevice * s, int n_chan,unsigned int *chanlist| -| ,char check) | -| | -+----------------------------------------------------------------------------+ -| Task :This function will first check channel list is ok or not| -|and then initialize the sequence RAM with the polarity, Gain,Channel number | -|If the last argument of function "check"is 1 then it only checks the channel| -|list is ok or not. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device * dev | -| struct comedi_subdevice * s | -| int n_chan | - unsigned int *chanlist - char check -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ + * 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 | + APCI3120_ENABLE_WRITE_TC_INT), + devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); -int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s, - int n_chan, unsigned int *chanlist, char check) -{ - unsigned int i; /* , differencial=0, bipolar=0; */ - unsigned int gain; - unsigned short us_TmpValue; + } + if (samplesinbuf) { + v_APCI3120_InterruptDmaMoveBlock16bit(dev, s, + devpriv->ul_DmaBufferVirtual[devpriv-> + ui_DmaActualBuffer], samplesinbuf); - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - if (!check) - comedi_error(dev, "range/channel list is empty!"); - return 0; + if (!(cmd->flags & TRIG_WAKE_EOS)) { + s->async->events |= COMEDI_CB_EOS; + comedi_event(dev, s); + } } - /* All is ok, so we can setup channel/range list */ - if (check) - return 1; + if (cmd->stop_src == TRIG_COUNT) + if (devpriv->ui_AiActualScan >= cmd->stop_arg) { + /* all data sampled */ + apci3120_cancel(dev, s); + s->async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); + return; + } - /* 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; - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); + 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 + */ + ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; + outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); - for (i = 0; i < n_chan; i++) { - /* store range list to card */ - us_TmpValue = CR_CHAN(chanlist[i]); /* get channel number; */ + /* changed since 16 bit interface for add on */ + outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); + 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 + */ + outl(APCI3120_A2P_FIFO_MANAGEMENT, + devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); - if (CR_RANGE(chanlist[i]) < APCI3120_BIPOLAR_RANGES) - us_TmpValue &= ((~APCI3120_UNIPOLAR) & 0xff); /* set bipolar */ - else - us_TmpValue |= APCI3120_UNIPOLAR; /* enable unipolar...... */ + var = devpriv->ul_DmaBufferHw[0]; + low_word = var & 0xffff; + var = devpriv->ul_DmaBufferHw[0]; + high_word = var / 65536; + outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); + outw(low_word, devpriv->i_IobaseAddon + 2); + outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); + outw(high_word, devpriv->i_IobaseAddon + 2); - 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.... */ - outw(us_TmpValue, dev->iobase + APCI3120_SEQ_RAM_ADDRESS); + var = devpriv->ui_DmaBufferUsesize[0]; + low_word = var & 0xffff; /* changed */ + var = devpriv->ui_DmaBufferUsesize[0]; + high_word = var / 65536; + outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); + outw(low_word, devpriv->i_IobaseAddon + 2); + outw(APCI3120_ADD_ON_MWTC_HIGH, devpriv->i_IobaseAddon + 0); + outw(high_word, devpriv->i_IobaseAddon + 2); - printk("\n Gain = %i", - (((unsigned char)CR_RANGE(chanlist[i]) & 0x03) << 2)); - printk("\n Channel = %i", CR_CHAN(chanlist[i])); - printk("\n Polarity = %i", us_TmpValue & APCI3120_UNIPOLAR); +/* + * 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 | + APCI3120_ENABLE_WRITE_TC_INT), + devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); } - return 1; /* we can serve this with scan logic */ } /* -+----------------------------------------------------------------------------+ -| Function name : int i_APCI3120_ExttrigEnable(struct comedi_device * dev) | -| | -| | -+----------------------------------------------------------------------------+ -| Task : Enable the external trigger | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device * dev | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_ExttrigEnable(struct comedi_device *dev) + * This function handles EOS interrupt. + * This function copies the acquired data(from FIFO) to Comedi buffer. + */ +static int apci3120_interrupt_handle_eos(struct comedi_device *dev) { + struct addi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + int n_chan, i; + int err = 1; - devpriv->us_OutputRegister |= APCI3120_ENABLE_EXT_TRIGGER; - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - return 0; -} + n_chan = devpriv->ui_AiNbrofChannels; -/* -+----------------------------------------------------------------------------+ -| Function name : int i_APCI3120_ExttrigDisable(struct comedi_device * dev) | -| | -+----------------------------------------------------------------------------+ -| Task : Disables the external trigger | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device * dev | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -| | -+----------------------------------------------------------------------------+ -*/ + for (i = 0; i < n_chan; i++) + err &= comedi_buf_put(s, inw(dev->iobase + 0)); -int i_APCI3120_ExttrigDisable(struct comedi_device *dev) -{ - devpriv->us_OutputRegister &= ~APCI3120_ENABLE_EXT_TRIGGER; - outw(devpriv->us_OutputRegister, dev->iobase + APCI3120_WR_ADDRESS); - return 0; -} + s->async->events |= COMEDI_CB_EOS; -/* -+----------------------------------------------------------------------------+ -| intERRUPT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ + if (err == 0) + s->async->events |= COMEDI_CB_OVERFLOW; -/* -+----------------------------------------------------------------------------+ -| Function name : void v_APCI3120_Interrupt(int irq, void *d) | -| | -| | -+----------------------------------------------------------------------------+ -| Task :Interrupt handler for APCI3120 | -| When interrupt occurs this gets called. | -| First it finds which interrupt has been generated and | -| handles corresponding interrupt | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq | -| void *d | -| | -+----------------------------------------------------------------------------+ -| Return Value : void | -| | -+----------------------------------------------------------------------------+ -*/ + comedi_event(dev, s); -void v_APCI3120_Interrupt(int irq, void *d) + return 0; +} + +static void apci3120_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct addi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; unsigned short int_daq; - unsigned int int_amcc, ui_Check, i; unsigned short us_TmpValue; unsigned char b_DummyRead; - struct comedi_subdevice *s = dev->subdevices + 0; ui_Check = 1; int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */ @@ -1468,7 +1558,7 @@ void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_ExttrigEnable == APCI3120_ENABLE) { /* Disable ext trigger */ - i_APCI3120_ExttrigDisable(dev); + apci3120_exttrig_disable(dev); devpriv->b_ExttrigEnable = APCI3120_DISABLE; } /* clear the timer 2 interrupt */ @@ -1506,9 +1596,9 @@ void v_APCI3120_Interrupt(int irq, void *d) if (devpriv->b_EocEosInterrupt == APCI3120_ENABLE) { /* enable this in without DMA ??? */ - if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { + if (devpriv->ai_running) { ui_Check = 0; - i_APCI3120_InterruptHandleEos(dev); + apci3120_interrupt_handle_eos(dev); devpriv->ui_AiActualScan++; devpriv->b_ModeSelectRegister = devpriv-> @@ -1548,8 +1638,6 @@ void v_APCI3120_Interrupt(int irq, void *d) switch (devpriv->b_Timer2Mode) { case APCI3120_COUNTER: - - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; devpriv->b_ModeSelectRegister = devpriv-> b_ModeSelectRegister & APCI3120_DISABLE_EOS_INT; @@ -1564,8 +1652,7 @@ void v_APCI3120_Interrupt(int irq, void *d) dev->iobase + APCI3120_WR_ADDRESS); /* stop timer 0 and timer 1 */ - i_APCI3120_StopCyclicAcquisition(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; + apci3120_cancel(dev, s); /* UPDATE-0.7.57->0.7.68comedi_done(dev,s); */ s->async->events |= COMEDI_CB_EOA; @@ -1604,7 +1691,7 @@ void v_APCI3120_Interrupt(int irq, void *d) } if ((int_daq & 0x4) && (devpriv->b_InterruptMode == APCI3120_DMA_MODE)) { - if (devpriv->b_AiCyclicAcquisition == APCI3120_ENABLE) { + if (devpriv->ai_running) { /****************************/ /* Clear Timer Write TC int */ @@ -1618,7 +1705,8 @@ void v_APCI3120_Interrupt(int irq, void *d) /* Clears the timer status register */ /************************************/ inw(dev->iobase + APCI3120_TIMER_STATUS_REGISTER); - v_APCI3120_InterruptDma(irq, d); /* do some data transfer */ + /* do some data transfer */ + apci3120_interrupt_dma(irq, d); } else { /* Stops the Timer */ outw(devpriv-> @@ -1633,284 +1721,20 @@ void v_APCI3120_Interrupt(int irq, void *d) } /* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) | -| | -| | -+----------------------------------------------------------------------------+ -| Task : This function handles EOS interrupt. | -| This function copies the acquired data(from FIFO) | -| to Comedi buffer. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| | -| | -+----------------------------------------------------------------------------+ -| Return Value : 0 | -| | -+----------------------------------------------------------------------------+ -*/ - - -int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) -{ - int n_chan, i; - struct comedi_subdevice *s = dev->subdevices + 0; - int err = 1; - - n_chan = devpriv->ui_AiNbrofChannels; - - s->async->events = 0; - - for (i = 0; i < n_chan; i++) - err &= comedi_buf_put(s->async, inw(dev->iobase + 0)); - - s->async->events |= COMEDI_CB_EOS; - - if (err == 0) - s->async->events |= COMEDI_CB_OVERFLOW; - - comedi_event(dev, s); - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function name : void v_APCI3120_InterruptDma(int irq, void *d) | -| | -+----------------------------------------------------------------------------+ -| Task : This is a handler for the DMA interrupt | -| This function copies the data to Comedi Buffer. | -| For continuous DMA it reinitializes the DMA operation. | -| For single mode DMA it stop the acquisition. | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq, void *d | -| | -+----------------------------------------------------------------------------+ -| Return Value : void | -| | -+----------------------------------------------------------------------------+ -*/ - -void v_APCI3120_InterruptDma(int irq, void *d) -{ - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - unsigned int next_dma_buf, samplesinbuf; - unsigned long low_word, high_word, var; - - unsigned int ui_Tmp; - samplesinbuf = - devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer] - - inl(devpriv->i_IobaseAmcc + AMCC_OP_REG_MWTC); - - if (samplesinbuf < - devpriv->ui_DmaBufferUsesize[devpriv->ui_DmaActualBuffer]) { - comedi_error(dev, "Interrupted DMA transfer!"); - } - if (samplesinbuf & 1) { - comedi_error(dev, "Odd count of bytes in DMA ring!"); - i_APCI3120_StopCyclicAcquisition(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; - - return; - } - samplesinbuf = samplesinbuf >> 1; /* number of received samples */ - if (devpriv->b_DmaDoubleBuffer) { - /* switch DMA buffers if is used double buffering */ - next_dma_buf = 1 - devpriv->ui_DmaActualBuffer; - - ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; - outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); - - /* changed since 16 bit interface for add on */ - outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); - 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); /* 0x1000 is out putted in windows driver */ - - var = devpriv->ul_DmaBufferHw[next_dma_buf]; - low_word = var & 0xffff; - var = devpriv->ul_DmaBufferHw[next_dma_buf]; - high_word = var / 65536; - - /* DMA Start Address Low */ - outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); - outw(low_word, devpriv->i_IobaseAddon + 2); - - /* DMA Start Address High */ - outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); - outw(high_word, devpriv->i_IobaseAddon + 2); - - var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; - low_word = var & 0xffff; - var = devpriv->ui_DmaBufferUsesize[next_dma_buf]; - high_word = var / 65536; - - /* Nbr of acquisition LOW */ - outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); - outw(low_word, devpriv->i_IobaseAddon + 2); - - /* Nbr of acquisition HIGH */ - 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 - */ - 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 | - APCI3120_ENABLE_WRITE_TC_INT), - devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); - - } - if (samplesinbuf) { - v_APCI3120_InterruptDmaMoveBlock16bit(dev, s, - devpriv->ul_DmaBufferVirtual[devpriv-> - ui_DmaActualBuffer], samplesinbuf); - - if (!(devpriv->ui_AiFlags & TRIG_WAKE_EOS)) { - s->async->events |= COMEDI_CB_EOS; - comedi_event(dev, s); - } - } - if (!devpriv->b_AiContinuous) - if (devpriv->ui_AiActualScan >= devpriv->ui_AiNbrofScans) { - /* all data sampled */ - i_APCI3120_StopCyclicAcquisition(dev, s); - devpriv->b_AiCyclicAcquisition = APCI3120_DISABLE; - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; - } - - 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 - */ - ui_Tmp = AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO; - outl(ui_Tmp, devpriv->i_IobaseAddon + AMCC_OP_REG_AGCSTS); - - /* changed since 16 bit interface for add on */ - outw(APCI3120_ADD_ON_AGCSTS_LOW, devpriv->i_IobaseAddon + 0); - 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 - */ - outl(APCI3120_A2P_FIFO_MANAGEMENT, - devpriv->i_IobaseAmcc + AMCC_OP_REG_MCSR); - - var = devpriv->ul_DmaBufferHw[0]; - low_word = var & 0xffff; - var = devpriv->ul_DmaBufferHw[0]; - high_word = var / 65536; - outw(APCI3120_ADD_ON_MWAR_LOW, devpriv->i_IobaseAddon + 0); - outw(low_word, devpriv->i_IobaseAddon + 2); - outw(APCI3120_ADD_ON_MWAR_HIGH, devpriv->i_IobaseAddon + 0); - outw(high_word, devpriv->i_IobaseAddon + 2); - - var = devpriv->ui_DmaBufferUsesize[0]; - low_word = var & 0xffff; /* changed */ - var = devpriv->ui_DmaBufferUsesize[0]; - high_word = var / 65536; - outw(APCI3120_ADD_ON_MWTC_LOW, devpriv->i_IobaseAddon + 0); - outw(low_word, devpriv->i_IobaseAddon + 2); - 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 + * Configure Timer 2 + * + * data[0] = TIMER configure as timer + * = WATCHDOG configure as watchdog + * data[1] = Timer constant + * data[2] = Timer2 interrupt (1)enable or(0) disable */ - 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 | - APCI3120_ENABLE_WRITE_TC_INT), - devpriv->i_IobaseAmcc + AMCC_OP_REG_INTCSR); - } -} - -/* -+----------------------------------------------------------------------------+ -| Function name :void v_APCI3120_InterruptDmaMoveBlock16bit(comedi_device| -|*dev,struct comedi_subdevice *s,short *dma,short *data,int n) | -| | -+----------------------------------------------------------------------------+ -| Task : This function copies the data from DMA buffer to the | -| Comedi buffer | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| short *dma | -| short *data,int n | -+----------------------------------------------------------------------------+ -| Return Value : void | -| | -+----------------------------------------------------------------------------+ -*/ - -void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, - struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples) -{ - devpriv->ui_AiActualScan += - (s->async->cur_chan + num_samples) / devpriv->ui_AiScanLength; - s->async->cur_chan += num_samples; - s->async->cur_chan %= devpriv->ui_AiScanLength; - - cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); -} - -/* -+----------------------------------------------------------------------------+ -| TIMER SUBDEVICE | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, | -| struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task :Configure Timer 2 | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -| | -| data[0]= TIMER configure as timer | -| = WATCHDOG configure as watchdog | -| data[1] = Timer constant | -| data[2] = Timer2 interrupt (1)enable or(0) disable | -| | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int apci3120_config_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - + const struct addi_board *this_board = comedi_board(dev); + struct addi_private *devpriv = dev->private; unsigned int ui_Timervalue2; unsigned short us_TmpValue; unsigned char b_Tmp; @@ -1922,7 +1746,7 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevic ui_Timervalue2 = data[1] / 1000; /* convert nano seconds to u seconds */ - /* this_board->i_hwdrv_InsnConfigTimer(dev, ui_Timervalue2,(unsigned char)data[0]); */ + /* this_board->timer_config(dev, ui_Timervalue2,(unsigned char)data[0]); */ us_TmpValue = (unsigned short) inw(devpriv->iobase + APCI3120_RD_STATUS); /* @@ -2038,37 +1862,24 @@ int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevic } /* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, | -| struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : To start and stop the timer | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -| | -| data[0] = 1 (start) | -| data[0] = 0 (stop ) | -| data[0] = 2 (write new value) | -| data[1]= new value | -| | -| devpriv->b_Timer2Mode = 0 DISABLE | -| 1 Timer | -| 2 Watch dog | -| | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * To start and stop the timer + * + * data[0] = 1 (start) + * = 0 (stop) + * = 2 (write new value) + * data[1] = new value + * + * devpriv->b_Timer2Mode = 0 DISABLE + * = 1 Timer + * = 2 Watch dog + */ +static int apci3120_write_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - + const struct addi_board *this_board = comedi_board(dev); + struct addi_private *devpriv = dev->private; unsigned int ui_Timervalue2 = 0; unsigned short us_TmpValue; unsigned char b_Tmp; @@ -2092,7 +1903,7 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice ui_Timervalue2 = 0; } - /* this_board->i_hwdrv_InsnWriteTimer(dev,data[0],ui_Timervalue2); */ + /* this_board->timer_write(dev,data[0],ui_Timervalue2); */ switch (data[0]) { case APCI3120_START: @@ -2227,31 +2038,19 @@ int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice } /* -+----------------------------------------------------------------------------+ -| Function name : int i_APCI3120_InsnReadTimer(struct comedi_device *dev, | -| struct comedi_subdevice *s,struct comedi_insn *insn, unsigned int *data) | -| | -| | -+----------------------------------------------------------------------------+ -| Task : read the Timer value | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -| | -+----------------------------------------------------------------------------+ -| Return Value : | -| for Timer: data[0]= Timer constant | -| | -| for watchdog: data[0]=0 (still running) | -| data[0]=1 (run down) | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + * Read the Timer value + * + * for Timer: data[0]= Timer constant + * + * for watchdog: data[0] = 0 (still running) + * = 1 (run down) + */ +static int apci3120_read_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned char b_Tmp; unsigned short us_TmpValue, us_TmpValue_2, us_StatusValue; @@ -2260,7 +2059,7 @@ int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice comedi_error(dev, "\nread:timer2 not configured "); } - /* this_board->i_hwdrv_InsnReadTimer(dev,data); */ + /* this_board->timer_read(dev,data); */ if (devpriv->b_Timer2Mode == APCI3120_TIMER) { /* Read the LOW unsigned short of Timer 2 register */ @@ -2296,306 +2095,54 @@ int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice return insn->n; } -/* -+----------------------------------------------------------------------------+ -| DIGITAL INPUT SUBDEVICE | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, | -| struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | -| | -| | -+----------------------------------------------------------------------------+ -| Task : Reads the value of the specified Digital input channel| -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int ui_Chan, ui_TmpValue; - - ui_Chan = CR_CHAN(insn->chanspec); /* channel specified */ + struct addi_private *devpriv = dev->private; + unsigned int val; - /* this_board->i_hwdrv_InsnReadDigitalInput(dev,ui_Chan,data); */ - if (ui_Chan <= 3) { - ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS); - -/* - * since only 1 channel reqd to bring it to last bit it is rotated 8 - * +(chan - 1) times then ANDed with 1 for last bit. - */ - *data = (ui_TmpValue >> (ui_Chan + 8)) & 1; - /* return 0; */ - } else { - /* comedi_error(dev," chan spec wrong"); */ - return -EINVAL; /* "sorry channel spec wrong " */ - } - return insn->n; - -} - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, | -|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Reads the value of the Digital input Port i.e.4channels| -| value is returned in data[0] | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_TmpValue; - ui_TmpValue = (unsigned int) inw(devpriv->iobase + APCI3120_RD_STATUS); - /***** state of 4 channels in the 11, 10, 9, 8 bits of status reg - rotated right 8 times to bring them to last four bits - ANDed with oxf for value. - *****/ - - *data = (ui_TmpValue >> 8) & 0xf; - /* this_board->i_hwdrv_InsnBitsDigitalInput(dev,data); */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| DIGITAL OUTPUT SUBDEVICE | -+----------------------------------------------------------------------------+ -*/ -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device | -| *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task :Configure the output memory ON or OFF | -| | -+----------------------------------------------------------------------------+ -| Input Parameters :struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) -{ - - if ((data[0] != 0) && (data[0] != 1)) { - comedi_error(dev, - "Not a valid Data !!! ,Data should be 1 or 0\n"); - return -EINVAL; - } - if (data[0]) { - devpriv->b_OutputMemoryStatus = APCI3120_ENABLE; - - } else { - devpriv->b_OutputMemoryStatus = APCI3120_DISABLE; - devpriv->b_DigitalOutputRegister = 0; - } - if (!devpriv->b_OutputMemoryStatus) - ui_Temp = 0; - /* if(!devpriv->b_OutputMemoryStatus ) */ - - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, | -| struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : write diatal output port | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -| data[0] Value to be written -| data[1] :1 Set digital o/p ON -| data[1] 2 Set digital o/p OFF with memory ON -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if ((data[0] > devpriv->s_EeParameters.i_DoMaxdata) || (data[0] < 0)) { - - comedi_error(dev, "Data is not valid !!! \n"); - return -EINVAL; - } - - switch (data[1]) { - case 1: - data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister; - break; - - case 2: - data[0] = data[0]; - break; - default: - printk("\nThe parameter passed is in error \n"); - return -EINVAL; - } /* switch(data[1]) */ - outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT); - - devpriv->b_DigitalOutputRegister = data[0] & 0xF0; + /* the input channels are bits 11:8 of the status reg */ + val = inw(devpriv->iobase + APCI3120_RD_STATUS); + data[1] = (val >> 8) & 0xf; return insn->n; - } -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev,| -|struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Write digiatl output | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | - data[0] Value to be written - data[1] :1 Set digital o/p ON - data[1] 2 Set digital o/p OFF with memory ON -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; - unsigned int ui_Temp1; - - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ + if (comedi_dio_update_state(s, data)) { + /* The do channels are bits 7:4 of the do register */ + devpriv->b_DigitalOutputRegister = s->state << 4; - if ((data[0] != 0) && (data[0] != 1)) { - comedi_error(dev, - "Not a valid Data !!! ,Data should be 1 or 0\n"); - return -EINVAL; - } - if (ui_NoOfChannel > devpriv->s_EeParameters.i_NbrDoChannel - 1) { - comedi_error(dev, - "This board doesn't have specified channel !!! \n"); - return -EINVAL; + outb(devpriv->b_DigitalOutputRegister, + devpriv->iobase + APCI3120_DIGITAL_OUTPUT); } - switch (data[1]) { - case 1: - data[0] = (data[0] << ui_NoOfChannel); -/* ES05 data[0]=(data[0]<<4)|ui_Temp; */ - data[0] = (data[0] << 4) | devpriv->b_DigitalOutputRegister; - break; + data[1] = s->state; - case 2: - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp1 = ui_Temp1 << 4; -/* ES05 ui_Temp=ui_Temp|ui_Temp1; */ - devpriv->b_DigitalOutputRegister = - devpriv->b_DigitalOutputRegister | ui_Temp1; - - data[0] = (data[0] << ui_NoOfChannel) ^ 0xf; - data[0] = data[0] << 4; -/* ES05 data[0]=data[0]& ui_Temp; */ - data[0] = data[0] & devpriv->b_DigitalOutputRegister; - break; - default: - printk("\nThe parameter passed is in error \n"); - return -EINVAL; - } /* switch(data[1]) */ - outb(data[0], devpriv->iobase + APCI3120_DIGITAL_OUTPUT); - -/* ES05 ui_Temp=data[0] & 0xf0; */ - devpriv->b_DigitalOutputRegister = data[0] & 0xf0; return insn->n; - } -/* -+----------------------------------------------------------------------------+ -| ANALOG OUTPUT SUBDEVICE | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev,| -|struct comedi_subdevice *s, struct comedi_insn *insn,unsigned int *data) | -| | -+----------------------------------------------------------------------------+ -| Task : Write analog output | -| | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -| struct comedi_subdevice *s | -| struct comedi_insn *insn | -| unsigned int *data | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int apci3120_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_Range, ui_Channel; unsigned short us_TmpValue; ui_Range = CR_RANGE(insn->chanspec); ui_Channel = CR_CHAN(insn->chanspec); - /* this_board->i_hwdrv_InsnWriteAnalogOutput(dev, ui_Range, ui_Channel,data[0]); */ + /* this_board->ao_write(dev, ui_Range, ui_Channel,data[0]); */ if (ui_Range) { /* if 1 then unipolar */ if (data[0] != 0) diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h deleted file mode 100644 index 50eb0a0a0a0..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.h +++ /dev/null @@ -1,249 +0,0 @@ - -/* hwdrv_apci3120.h */ - -/* - * 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. - */ - -/* comedi related defines */ - -/* ANALOG INPUT RANGE */ -static const struct comedi_lrange range_apci3120_ai = { 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -/* ANALOG OUTPUT RANGE */ -static const struct comedi_lrange range_apci3120_ao = { 2, { - BIP_RANGE(10), - UNI_RANGE(10) - } -}; - -#define APCI3120_BIPOLAR_RANGES 4 /* used for test on mixture of BIP/UNI ranges */ - -#define APCI3120_BOARD_VENDOR_ID 0x10E8 -#define APCI3120_ADDRESS_RANGE 16 - -#define APCI3120_DISABLE 0 -#define APCI3120_ENABLE 1 - -#define APCI3120_START 1 -#define APCI3120_STOP 0 - -#define APCI3120_EOC_MODE 1 -#define APCI3120_EOS_MODE 2 -#define APCI3120_DMA_MODE 3 - -/* DIGITAL INPUT-OUTPUT DEFINE */ - -#define APCI3120_DIGITAL_OUTPUT 0x0D -#define APCI3120_RD_STATUS 0x02 -#define APCI3120_RD_FIFO 0x00 - -/* digital output insn_write ON /OFF selection */ -#define APCI3120_SET4DIGITALOUTPUTON 1 -#define APCI3120_SET4DIGITALOUTPUTOFF 0 - -/* analog output SELECT BIT */ -#define APCI3120_ANALOG_OP_CHANNEL_1 0x0000 -#define APCI3120_ANALOG_OP_CHANNEL_2 0x4000 -#define APCI3120_ANALOG_OP_CHANNEL_3 0x8000 -#define APCI3120_ANALOG_OP_CHANNEL_4 0xC000 -#define APCI3120_ANALOG_OP_CHANNEL_5 0x0000 -#define APCI3120_ANALOG_OP_CHANNEL_6 0x4000 -#define APCI3120_ANALOG_OP_CHANNEL_7 0x8000 -#define APCI3120_ANALOG_OP_CHANNEL_8 0xC000 - -/* Enable external trigger bit in nWrAddress */ -#define APCI3120_ENABLE_EXT_TRIGGER 0x8000 - -/* ANALOG OUTPUT AND INPUT DEFINE */ -#define APCI3120_UNIPOLAR 0x80 /* $$ RAM sequence polarity BIT */ -#define APCI3120_BIPOLAR 0x00 /* $$ RAM sequence polarity BIT */ -#define APCI3120_ANALOG_OUTPUT_1 0x08 /* (ADDRESS ) */ -#define APCI3120_ANALOG_OUTPUT_2 0x0A /* (ADDRESS ) */ -#define APCI3120_1_GAIN 0x00 /* $$ RAM sequence Gain Bits for gain 1 */ -#define APCI3120_2_GAIN 0x10 /* $$ RAM sequence Gain Bits for gain 2 */ -#define APCI3120_5_GAIN 0x20 /* $$ RAM sequence Gain Bits for gain 5 */ -#define APCI3120_10_GAIN 0x30 /* $$ RAM sequence Gain Bits for gain 10 */ -#define APCI3120_SEQ_RAM_ADDRESS 0x06 /* $$ EARLIER NAMED APCI3120_FIFO_ADDRESS */ -#define APCI3120_RESET_FIFO 0x0C /* (ADDRESS) */ -#define APCI3120_TIMER_0_MODE_2 0x01 /* $$ Bits for timer mode */ -#define APCI3120_TIMER_0_MODE_4 0x2 -#define APCI3120_SELECT_TIMER_0_WORD 0x00 -#define APCI3120_ENABLE_TIMER0 0x1000 /* $$Gatebit 0 in nWrAddress */ -#define APCI3120_CLEAR_PR 0xF0FF -#define APCI3120_CLEAR_PA 0xFFF0 -#define APCI3120_CLEAR_PA_PR (APCI3120_CLEAR_PR & APCI3120_CLEAR_PA) - -/* nWrMode_Select */ -#define APCI3120_ENABLE_SCAN 0x8 /* $$ bit in nWrMode_Select */ -#define APCI3120_DISABLE_SCAN (~APCI3120_ENABLE_SCAN) -#define APCI3120_ENABLE_EOS_INT 0x2 /* $$ bit in nWrMode_Select */ - -#define APCI3120_DISABLE_EOS_INT (~APCI3120_ENABLE_EOS_INT) -#define APCI3120_ENABLE_EOC_INT 0x1 -#define APCI3120_DISABLE_EOC_INT (~APCI3120_ENABLE_EOC_INT) -#define APCI3120_DISABLE_ALL_INTERRUPT_WITHOUT_TIMER (APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT) -#define APCI3120_DISABLE_ALL_INTERRUPT (APCI3120_DISABLE_TIMER_INT & APCI3120_DISABLE_EOS_INT & APCI3120_DISABLE_EOC_INT) - -/* status register bits */ -#define APCI3120_EOC 0x8000 -#define APCI3120_EOS 0x2000 - -/* software trigger dummy register */ -#define APCI3120_START_CONVERSION 0x02 /* (ADDRESS) */ - -/* TIMER DEFINE */ -#define APCI3120_QUARTZ_A 70 -#define APCI3120_QUARTZ_B 50 -#define APCI3120_TIMER 1 -#define APCI3120_WATCHDOG 2 -#define APCI3120_TIMER_DISABLE 0 -#define APCI3120_TIMER_ENABLE 1 -#define APCI3120_ENABLE_TIMER2 0x4000 /* $$ gatebit 2 in nWrAddress */ -#define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2) -#define APCI3120_ENABLE_TIMER_INT 0x04 /* $$ ENAIRQ_FC_Bit in nWrModeSelect */ -#define APCI3120_DISABLE_TIMER_INT (~APCI3120_ENABLE_TIMER_INT) -#define APCI3120_WRITE_MODE_SELECT 0x0E /* (ADDRESS) */ -#define APCI3120_SELECT_TIMER_0_WORD 0x00 -#define APCI3120_SELECT_TIMER_1_WORD 0x01 -#define APCI3120_TIMER_1_MODE_2 0x4 - -/* $$ BIT FOR MODE IN nCsTimerCtr1 */ -#define APCI3120_TIMER_2_MODE_0 0x0 -#define APCI3120_TIMER_2_MODE_2 0x10 -#define APCI3120_TIMER_2_MODE_5 0x30 - -/* $$ BIT FOR MODE IN nCsTimerCtr0 */ -#define APCI3120_SELECT_TIMER_2_LOW_WORD 0x02 -#define APCI3120_SELECT_TIMER_2_HIGH_WORD 0x03 - -#define APCI3120_TIMER_CRT0 0x0D /* (ADDRESS for cCsTimerCtr0) */ -#define APCI3120_TIMER_CRT1 0x0C /* (ADDRESS for cCsTimerCtr1) */ - -#define APCI3120_TIMER_VALUE 0x04 /* ADDRESS for nCsTimerWert */ -#define APCI3120_TIMER_STATUS_REGISTER 0x0D /* ADDRESS for delete timer 2 interrupt */ -#define APCI3120_RD_STATUS 0x02 /* ADDRESS */ -#define APCI3120_WR_ADDRESS 0x00 /* ADDRESS */ -#define APCI3120_ENABLE_WATCHDOG 0x20 /* $$BIT in nWrMode_Select */ -#define APCI3120_DISABLE_WATCHDOG (~APCI3120_ENABLE_WATCHDOG) -#define APCI3120_ENABLE_TIMER_COUNTER 0x10 /* $$BIT in nWrMode_Select */ -#define APCI3120_DISABLE_TIMER_COUNTER (~APCI3120_ENABLE_TIMER_COUNTER) -#define APCI3120_FC_TIMER 0x1000 /* bit in status register */ -#define APCI3120_ENABLE_TIMER0 0x1000 -#define APCI3120_ENABLE_TIMER1 0x2000 -#define APCI3120_ENABLE_TIMER2 0x4000 -#define APCI3120_DISABLE_TIMER0 (~APCI3120_ENABLE_TIMER0) -#define APCI3120_DISABLE_TIMER1 (~APCI3120_ENABLE_TIMER1) -#define APCI3120_DISABLE_TIMER2 (~APCI3120_ENABLE_TIMER2) - -#define APCI3120_TIMER2_SELECT_EOS 0xC0 /* ADDED on 20-6 */ -#define APCI3120_COUNTER 3 /* on 20-6 */ -#define APCI3120_DISABLE_ALL_TIMER (APCI3120_DISABLE_TIMER0 & APCI3120_DISABLE_TIMER1 & APCI3120_DISABLE_TIMER2) /* on 20-6 */ - -#define MAX_ANALOGINPUT_CHANNELS 32 - -struct str_AnalogReadInformation { - - unsigned char b_Type; /* EOC or EOS */ - unsigned char b_InterruptFlag; /* Interrupt use or not */ - unsigned int ui_ConvertTiming; /* Selection of the conversion time */ - unsigned char b_NbrOfChannel; /* Number of channel to read */ - unsigned int ui_ChannelList[MAX_ANALOGINPUT_CHANNELS]; /* Number of the channel to be read */ - unsigned int ui_RangeList[MAX_ANALOGINPUT_CHANNELS]; /* Gain of each channel */ - -}; - - -/* Function Declaration For APCI-3120 */ - -/* Internal functions */ -int i_APCI3120_SetupChannelList(struct comedi_device *dev, struct comedi_subdevice *s, - int n_chan, unsigned int *chanlist, char check); -int i_APCI3120_ExttrigEnable(struct comedi_device *dev); -int i_APCI3120_ExttrigDisable(struct comedi_device *dev); -int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s); -int i_APCI3120_Reset(struct comedi_device *dev); -int i_APCI3120_CyclicAnalogInput(int mode, struct comedi_device *dev, - struct comedi_subdevice *s); -/* Interrupt functions */ -void v_APCI3120_Interrupt(int irq, void *d); -/* UPDATE-0.7.57->0.7.68 void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev,struct comedi_subdevice *s,short *dma,short *data,int n); */ -void v_APCI3120_InterruptDmaMoveBlock16bit(struct comedi_device *dev, - struct comedi_subdevice *s, - short *dma_buffer, - unsigned int num_samples); -int i_APCI3120_InterruptHandleEos(struct comedi_device *dev); -void v_APCI3120_InterruptDma(int irq, void *d); - -/* TIMER */ - -int i_APCI3120_InsnConfigTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3120_InsnWriteTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3120_InsnReadTimer(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* -* DI for di read -*/ - -int i_APCI3120_InsnBitsDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3120_InsnReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* DO */ -/* int i_APCI3120_WriteDigitalOutput(struct comedi_device *dev, - * unsigned char data); - */ -int i_APCI3120_InsnConfigDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -int i_APCI3120_InsnBitsDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3120_InsnWriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* AO */ -/* int i_APCI3120_Write1AnalogValue(struct comedi_device *dev,UINT ui_Range, - * UINT ui_Channel,UINT data ); - */ - -int i_APCI3120_InsnWriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* AI HArdware layer */ - -int i_APCI3120_InsnConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3120_InsnReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -int i_APCI3120_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s); -/* int i_APCI3120_CancelAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s); */ -int i_APCI3120_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index c75a1a1fd77..f540394d17b 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -15,10 +15,6 @@ This program is free software; you can redistribute it and/or modify it under th This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - @endverbatim */ /* @@ -51,17 +47,130 @@ You should also find the complete GPL in the COPYING file accompanying this sour +----------+-----------+------------------------------------------------+ */ -/* - +----------------------------------------------------------------------------+ - | Included files | - +----------------------------------------------------------------------------+ -*/ -#include "hwdrv_apci3200.h" -/* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ -#include "addi_amcc_S5920.h" /* #define PRINT_INFO */ -/* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ +/* Card Specific information */ +/* #define APCI3200_ADDRESS_RANGE 264 */ + +/* Analog Input related Defines */ +#define APCI3200_AI_OFFSET_GAIN 0 +#define APCI3200_AI_SC_TEST 4 +#define APCI3200_AI_IRQ 8 +#define APCI3200_AI_AUTOCAL 12 +#define APCI3200_RELOAD_CONV_TIME_VAL 32 +#define APCI3200_CONV_TIME_TIME_BASE 36 +#define APCI3200_RELOAD_DELAY_TIME_VAL 40 +#define APCI3200_DELAY_TIME_TIME_BASE 44 +#define APCI3200_AI_MODULE1 0 +#define APCI3200_AI_MODULE2 64 +#define APCI3200_AI_MODULE3 128 +#define APCI3200_AI_MODULE4 192 +#define TRUE 1 +#define FALSE 0 +#define APCI3200_AI_EOSIRQ 16 +#define APCI3200_AI_EOS 20 +#define APCI3200_AI_CHAN_ID 24 +#define APCI3200_AI_CHAN_VAL 28 +#define ANALOG_INPUT 0 +#define TEMPERATURE 1 +#define RESISTANCE 2 + +#define ENABLE_EXT_TRIG 1 +#define ENABLE_EXT_GATE 2 +#define ENABLE_EXT_TRIG_GATE 3 + +#define APCI3200_MAXVOLT 2.5 +#define ADDIDATA_GREATER_THAN_TEST 0 +#define ADDIDATA_LESS_THAN_TEST 1 + +#define ADDIDATA_UNIPOLAR 1 +#define ADDIDATA_BIPOLAR 2 + +#define MAX_MODULE 4 + +/* ANALOG INPUT RANGE */ +static const struct comedi_lrange range_apci3200_ai = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1) + } +}; + +static const struct comedi_lrange range_apci3300_ai = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1) + } +}; + +int MODULE_NO; +struct { + int i_Gain; + int i_Polarity; + int i_OffsetRange; + int i_Coupling; + int i_SingleDiff; + int i_AutoCalibration; + unsigned int ui_ReloadValue; + unsigned int ui_TimeUnitReloadVal; + int i_Interrupt; + int i_ModuleSelection; +} Config_Parameters_Module1, Config_Parameters_Module2, + Config_Parameters_Module3, Config_Parameters_Module4; + + +struct str_ADDIDATA_RTDStruct { + unsigned int ul_NumberOfValue; + unsigned int *pul_ResistanceValue; + unsigned int *pul_TemperatureValue; +}; + +struct str_Module { + unsigned long ul_CurrentSourceCJC; + unsigned long ul_CurrentSource[5]; + unsigned long ul_GainFactor[8]; /* Gain Factor */ + unsigned int w_GainValue[10]; +}; + +struct str_BoardInfos { + + int i_CJCAvailable; + int i_CJCPolarity; + int i_CJCGain; + int i_InterruptFlag; + int i_ADDIDATAPolarity; + int i_ADDIDATAGain; + int i_AutoCalibration; + int i_ADDIDATAConversionTime; + int i_ADDIDATAConversionTimeUnit; + int i_ADDIDATAType; + int i_ChannelNo; + int i_ChannelCount; + int i_ScanType; + int i_FirstChannel; + int i_LastChannel; + int i_Sum; + int i_Offset; + unsigned int ui_Channel_num; + int i_Count; + int i_Initialised; + unsigned int ui_InterruptChannelValue[144]; /* Buffer */ + unsigned char b_StructInitialized; + /* 7 is the maximal number of channels */ + unsigned int ui_ScanValueArray[7 + 12]; + + int i_ConnectionType; + int i_NbrOfModule; + struct str_Module s_Module[MAX_MODULE]; +}; /* BEGIN JK 06.07.04: Management of sevrals boards */ /* @@ -90,29 +199,17 @@ You should also find the complete GPL in the COPYING file accompanying this sour struct str_BoardInfos s_BoardInfos[100]; /* 100 will be the max number of boards to be used */ /* END JK 06.07.04: Management of sevrals boards */ -/* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - -/*+----------------------------------------------------------------------------+*/ -/*| Function Name : int i_AddiHeaderRW_ReadEeprom |*/ -/*| (int i_NbOfWordsToRead, |*/ -/*| unsigned int dw_PCIBoardEepromAddress, |*/ -/*| unsigned short w_EepromStartAddress, |*/ -/*| unsigned short * pw_DataRead) |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Task : Read word from the 5920 eeprom. |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Input Parameters : int i_NbOfWordsToRead : Nbr. of word to read |*/ -/*| unsigned int dw_PCIBoardEepromAddress : Address of the eeprom |*/ -/*| unsigned short w_EepromStartAddress : Eeprom start address |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Output Parameters : unsigned short * pw_DataRead : Read data |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Return Value : - |*/ -/*+----------------------------------------------------------------------------+*/ - -int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, - unsigned int dw_PCIBoardEepromAddress, - unsigned short w_EepromStartAddress, unsigned short *pw_DataRead) +#define AMCC_OP_REG_MCSR 0x3c +#define EEPROM_BUSY 0x80000000 +#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ +#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ +#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ +#define NVCMD_BEGIN_WRITE (0x6 << 5) /* EEPROM begin write command */ + +static int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, + unsigned int dw_PCIBoardEepromAddress, + unsigned short w_EepromStartAddress, + unsigned short *pw_DataRead) { unsigned int dw_eeprom_busy = 0; int i_Counter = 0; @@ -239,20 +336,8 @@ int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, return 0; } -/*+----------------------------------------------------------------------------+*/ -/*| Function Name : void v_GetAPCI3200EepromCalibrationValue (void) |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Task : Read calibration value from the APCI-3200 eeprom. |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Input Parameters : - |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Output Parameters : - |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Return Value : - |*/ -/*+----------------------------------------------------------------------------+*/ - -void v_GetAPCI3200EepromCalibrationValue(unsigned int dw_PCIBoardEepromAddress, - struct str_BoardInfos *BoardInformations) +static void v_GetAPCI3200EepromCalibrationValue(unsigned int dw_PCIBoardEepromAddress, + struct str_BoardInfos *BoardInformations) { unsigned short w_AnalogInputMainHeaderAddress; unsigned short w_AnalogInputComponentAddress; @@ -446,9 +531,11 @@ void v_GetAPCI3200EepromCalibrationValue(unsigned int dw_PCIBoardEepromAddress, } } -int i_APCI3200_GetChannelCalibrationValue(struct comedi_device *dev, - unsigned int ui_Channel_num, unsigned int *CJCCurrentSource, - unsigned int *ChannelCurrentSource, unsigned int *ChannelGainFactor) +static int i_APCI3200_GetChannelCalibrationValue(struct comedi_device *dev, + unsigned int ui_Channel_num, + unsigned int *CJCCurrentSource, + unsigned int *ChannelCurrentSource, + unsigned int *ChannelGainFactor) { int i_DiffChannel = 0; int i_Module = 0; @@ -518,1135 +605,41 @@ int i_APCI3200_GetChannelCalibrationValue(struct comedi_device *dev, return 0; } -/* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ReadDigitalInput | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read value of the selected channel or port | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int ui_NoOfChannels : No Of Channels To read for Port - Channel Numberfor single channel - | unsigned int data[0] : 0: Read single channel - 1: Read port value - data[1] Port number - +----------------------------------------------------------------------------+ - | Output Parameters : -- data[0] :Read status value - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ - -int i_APCI3200_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp = 0; - unsigned int ui_NoOfChannel = 0; - ui_NoOfChannel = CR_CHAN(insn->chanspec); - ui_Temp = data[0]; - *data = inl(devpriv->i_IobaseReserved); - - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if (ui_Temp==0) */ - else { - if (ui_Temp == 1) { - if (data[1] < 0 || data[1] > 1) { - printk("\nThe port number is in error\n"); - return -EINVAL; - } /* if(data[1] < 0 || data[1] >1) */ - switch (ui_NoOfChannel) { - - case 2: - *data = (*data >> (2 * data[1])) & 0x3; - break; - case 3: - *data = (*data & 15); - break; - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - - } /* switch(ui_NoOfChannels) */ - } /* if (ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* elseif (ui_Temp==1) */ - } - return insn->n; -} - -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ConfigDigitalOutput | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Configures The Digital Output Subdevice. | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | data[0] :1 Memory enable - 0 Memory Disable - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int apci3200_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; - if ((data[0] != 0) && (data[0] != 1)) { - comedi_error(dev, - "Not a valid Data !!! ,Data should be 1 or 0\n"); - return -EINVAL; - } /* if ( (data[0]!=0) && (data[0]!=1) ) */ - if (data[0]) { - devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } /* if (data[0]) */ - else { - devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } /* else if (data[0]) */ - return insn->n; -} - -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_WriteDigitalOutput | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : writes To the digital Output Subdevice | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | struct comedi_subdevice *s : Subdevice Pointer | - | struct comedi_insn *insn : Insn Structure Pointer | - | unsigned int *data : Data Pointer contains | - | configuration parameters as below | - | data[0] :Value to output - data[1] : 0 o/p single channel - 1 o/p port - data[2] : port no - data[3] :0 set the digital o/p on - 1 set the digital o/p off - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp = 0, ui_Temp1 = 0; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - if (devpriv->b_OutputMemoryStatus) { - ui_Temp = inl(devpriv->i_IobaseAddon); - - } /* if(devpriv->b_OutputMemoryStatus ) */ - else { - ui_Temp = 0; - } /* if(devpriv->b_OutputMemoryStatus ) */ - if (data[3] == 0) { - if (data[1] == 0) { - data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; - outl(data[0], devpriv->i_IobaseAddon); - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = - (data[0] << (2 * - data[2])) | ui_Temp; - break; - case 3: - data[0] = (data[0] | ui_Temp); - break; - } /* switch(ui_NoOfChannels) */ - - outl(data[0], devpriv->i_IobaseAddon); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==0) */ - else { - if (data[3] == 1) { - if (data[1] == 0) { - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = (data[0] << ui_NoOfChannel) ^ 0xf; - data[0] = data[0] & ui_Temp; - outl(data[0], devpriv->i_IobaseAddon); - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - switch (ui_NoOfChannel) { - - case 2: - data[0] = ~data[0] & 0x3; - ui_Temp1 = 3; - ui_Temp1 = - ui_Temp1 << 2 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (2 * - data - [2])) ^ - 0xf) & ui_Temp; - - break; - case 3: - break; - - default: - comedi_error(dev, - " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - } /* switch(ui_NoOfChannels) */ - - outl(data[0], devpriv->i_IobaseAddon); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==1); */ - else { - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* if else data[3]==1) */ - } /* if else data[3]==0) */ - return insn->n; -} - -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ReadDigitalOutput | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read value of the selected channel or port | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int ui_NoOfChannels : No Of Channels To read | - | unsigned int *data : Data Pointer to read status | - data[0] :0 read single channel - 1 read port value - data[1] port no - - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp; - unsigned int ui_NoOfChannel; - ui_NoOfChannel = CR_CHAN(insn->chanspec); - ui_Temp = data[0]; - *data = inl(devpriv->i_IobaseAddon); - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if (ui_Temp==0) */ - else { - if (ui_Temp == 1) { - if (data[1] < 0 || data[1] > 1) { - printk("\nThe port selection is in error\n"); - return -EINVAL; - } /* if(data[1] <0 ||data[1] >1) */ - switch (ui_NoOfChannel) { - case 2: - *data = (*data >> (2 * data[1])) & 3; - break; - - case 3: - break; - - default: - comedi_error(dev, " chan spec wrong"); - return -EINVAL; /* "sorry channel spec wrong " */ - break; - } /* switch(ui_NoOfChannels) */ - } /* if (ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* else if (ui_Temp==1) */ - } /* else if (ui_Temp==0) */ - return insn->n; -} - -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ConfigAnalogInput | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Configures The Analog Input Subdevice | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | struct comedi_subdevice *s : Subdevice Pointer | - | struct comedi_insn *insn : Insn Structure Pointer | - | unsigned int *data : Data Pointer contains | - | configuration parameters as below | - | | - | data[0] - | 0:Normal AI | - | 1:RTD | - | 2:THERMOCOUPLE | - | data[1] : Gain To Use | - | | - | data[2] : Polarity - | 0:Bipolar | - | 1:Unipolar | - | | - | data[3] : Offset Range - | | - | data[4] : Coupling - | 0:DC Coupling | - | 1:AC Coupling | - | | - | data[5] :Differential/Single - | 0:Single | - | 1:Differential | - | | - | data[6] :TimerReloadValue - | | - | data[7] :ConvertingTimeUnit - | | - | data[8] :0 Analog voltage measurement - 1 Resistance measurement - 2 Temperature measurement - | data[9] :Interrupt - | 0:Disable - | 1:Enable - data[10] :Type of Thermocouple - | data[11] : 0: single channel - Module Number - | - | data[12] - | 0:Single Read - | 1:Read more channel - 2:Single scan - | 3:Continuous Scan - data[13] :Number of channels to read - | data[14] :RTD connection type - :0:RTD not used - 1:RTD 2 wire connection - 2:RTD 3 wire connection - 3:RTD 4 wire connection - | | - | | - | | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - unsigned int ul_Config = 0, ul_Temp = 0; - unsigned int ui_ChannelNo = 0; - unsigned int ui_Dummy = 0; - int i_err = 0; - - /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - -#ifdef PRINT_INFO - int i = 0, i2 = 0; -#endif - /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* Initialize the structure */ - if (s_BoardInfos[dev->minor].b_StructInitialized != 1) { - s_BoardInfos[dev->minor].i_CJCAvailable = 1; - s_BoardInfos[dev->minor].i_CJCPolarity = 0; - s_BoardInfos[dev->minor].i_CJCGain = 2; /* changed from 0 to 2 */ - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - s_BoardInfos[dev->minor].i_AutoCalibration = 0; /* : auto calibration */ - s_BoardInfos[dev->minor].i_ChannelCount = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - s_BoardInfos[dev->minor].ui_Channel_num = 0; - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Initialised = 0; - s_BoardInfos[dev->minor].b_StructInitialized = 1; - - /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - s_BoardInfos[dev->minor].i_ConnectionType = 0; - /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - memset(s_BoardInfos[dev->minor].s_Module, 0, - sizeof(s_BoardInfos[dev->minor].s_Module[MAX_MODULE])); - - v_GetAPCI3200EepromCalibrationValue(devpriv->i_IobaseAmcc, - &s_BoardInfos[dev->minor]); - -#ifdef PRINT_INFO - for (i = 0; i < MAX_MODULE; i++) { - printk("\n s_Module[%i].ul_CurrentSourceCJC = %lu", i, - s_BoardInfos[dev->minor].s_Module[i]. - ul_CurrentSourceCJC); - - for (i2 = 0; i2 < 5; i2++) { - printk("\n s_Module[%i].ul_CurrentSource [%i] = %lu", i, i2, s_BoardInfos[dev->minor].s_Module[i].ul_CurrentSource[i2]); - } - - for (i2 = 0; i2 < 8; i2++) { - printk("\n s_Module[%i].ul_GainFactor [%i] = %lu", i, i2, s_BoardInfos[dev->minor].s_Module[i].ul_GainFactor[i2]); - } - - for (i2 = 0; i2 < 8; i2++) { - printk("\n s_Module[%i].w_GainValue [%i] = %u", - i, i2, - s_BoardInfos[dev->minor].s_Module[i]. - w_GainValue[i2]); - } - } -#endif - /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } - - if (data[0] != 0 && data[0] != 1 && data[0] != 2) { - printk("\nThe selection of acquisition type is in error\n"); - i_err++; - } /* if(data[0]!=0 && data[0]!=1 && data[0]!=2) */ - if (data[0] == 1) { - if (data[14] != 0 && data[14] != 1 && data[14] != 2 - && data[14] != 4) { - printk("\n Error in selection of RTD connection type\n"); - i_err++; - } /* if(data[14]!=0 && data[14]!=1 && data[14]!=2 && data[14]!=4) */ - } /* if(data[0]==1 ) */ - if (data[1] < 0 || data[1] > 7) { - printk("\nThe selection of gain is in error\n"); - i_err++; - } /* if(data[1]<0 || data[1]>7) */ - if (data[2] != 0 && data[2] != 1) { - printk("\nThe selection of polarity is in error\n"); - i_err++; - } /* if(data[2]!=0 && data[2]!=1) */ - if (data[3] != 0) { - printk("\nThe selection of offset range is in error\n"); - i_err++; - } /* if(data[3]!=0) */ - if (data[4] != 0 && data[4] != 1) { - printk("\nThe selection of coupling is in error\n"); - i_err++; - } /* if(data[4]!=0 && data[4]!=1) */ - if (data[5] != 0 && data[5] != 1) { - printk("\nThe selection of single/differential mode is in error\n"); - i_err++; - } /* if(data[5]!=0 && data[5]!=1) */ - if (data[8] != 0 && data[8] != 1 && data[2] != 2) { - printk("\nError in selection of functionality\n"); - } /* if(data[8]!=0 && data[8]!=1 && data[2]!=2) */ - if (data[12] == 0 || data[12] == 1) { - if (data[6] != 20 && data[6] != 40 && data[6] != 80 - && data[6] != 160) { - printk("\nThe selection of conversion time reload value is in error\n"); - i_err++; - } /* if (data[6]!=20 && data[6]!=40 && data[6]!=80 && data[6]!=160 ) */ - if (data[7] != 2) { - printk("\nThe selection of conversion time unit is in error\n"); - i_err++; - } /* if(data[7]!=2) */ - } - if (data[9] != 0 && data[9] != 1) { - printk("\nThe selection of interrupt enable is in error\n"); - i_err++; - } /* if(data[9]!=0 && data[9]!=1) */ - if (data[11] < 0 || data[11] > 4) { - printk("\nThe selection of module is in error\n"); - i_err++; - } /* if(data[11] <0 || data[11]>1) */ - if (data[12] < 0 || data[12] > 3) { - printk("\nThe selection of singlechannel/scan selection is in error\n"); - i_err++; - } /* if(data[12] < 0 || data[12]> 3) */ - if (data[13] < 0 || data[13] > 16) { - printk("\nThe selection of number of channels is in error\n"); - i_err++; - } /* if(data[13] <0 ||data[13] >15) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* - i_ChannelCount=data[13]; - i_ScanType=data[12]; - i_ADDIDATAPolarity = data[2]; - i_ADDIDATAGain=data[1]; - i_ADDIDATAConversionTime=data[6]; - i_ADDIDATAConversionTimeUnit=data[7]; - i_ADDIDATAType=data[0]; - */ - - /* Save acquisition configuration for the actual board */ - s_BoardInfos[dev->minor].i_ChannelCount = data[13]; - s_BoardInfos[dev->minor].i_ScanType = data[12]; - s_BoardInfos[dev->minor].i_ADDIDATAPolarity = data[2]; - s_BoardInfos[dev->minor].i_ADDIDATAGain = data[1]; - s_BoardInfos[dev->minor].i_ADDIDATAConversionTime = data[6]; - s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit = data[7]; - s_BoardInfos[dev->minor].i_ADDIDATAType = data[0]; - /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - s_BoardInfos[dev->minor].i_ConnectionType = data[5]; - /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* END JK 06.07.04: Management of sevrals boards */ - - /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - memset(s_BoardInfos[dev->minor].ui_ScanValueArray, 0, (7 + 12) * sizeof(unsigned int)); /* 7 is the maximal number of channels */ - /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /* BEGIN JK 02.07.04 : This while can't be do, it block the process when using severals boards */ - /* while(i_InterruptFlag==1) */ - while (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { -#ifndef MSXBOX - udelay(1); -#else - /* In the case where the driver is compiled for the MSX-Box */ - /* we used a printk to have a little delay because udelay */ - /* seems to be broken under the MSX-Box. */ - /* This solution hat to be studied. */ - printk(""); -#endif - } - /* END JK 02.07.04 : This while can't be do, it block the process when using severals boards */ - - ui_ChannelNo = CR_CHAN(insn->chanspec); /* get the channel */ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=ui_ChannelNo; */ - /* ui_Channel_num =ui_ChannelNo; */ - - s_BoardInfos[dev->minor].i_ChannelNo = ui_ChannelNo; - s_BoardInfos[dev->minor].ui_Channel_num = ui_ChannelNo; - - /* END JK 06.07.04: Management of sevrals boards */ - - if (data[5] == 0) { - if (ui_ChannelNo < 0 || ui_ChannelNo > 15) { - printk("\nThe Selection of the channel is in error\n"); - i_err++; - } /* if(ui_ChannelNo<0 || ui_ChannelNo>15) */ - } /* if(data[5]==0) */ - else { - if (data[14] == 2) { - if (ui_ChannelNo < 0 || ui_ChannelNo > 3) { - printk("\nThe Selection of the channel is in error\n"); - i_err++; - } /* if(ui_ChannelNo<0 || ui_ChannelNo>3) */ - } /* if(data[14]==2) */ - else { - if (ui_ChannelNo < 0 || ui_ChannelNo > 7) { - printk("\nThe Selection of the channel is in error\n"); - i_err++; - } /* if(ui_ChannelNo<0 || ui_ChannelNo>7) */ - } /* elseif(data[14]==2) */ - } /* elseif(data[5]==0) */ - if (data[12] == 0 || data[12] == 1) { - switch (data[5]) { - case 0: - if (ui_ChannelNo >= 0 && ui_ChannelNo <= 3) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo >=0 && ui_ChannelNo <=3) */ - if (ui_ChannelNo >= 4 && ui_ChannelNo <= 7) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=64; */ - s_BoardInfos[dev->minor].i_Offset = 64; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo >=4 && ui_ChannelNo <=7) */ - if (ui_ChannelNo >= 8 && ui_ChannelNo <= 11) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=128; */ - s_BoardInfos[dev->minor].i_Offset = 128; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo >=8 && ui_ChannelNo <=11) */ - if (ui_ChannelNo >= 12 && ui_ChannelNo <= 15) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=192; */ - s_BoardInfos[dev->minor].i_Offset = 192; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo >=12 && ui_ChannelNo <=15) */ - break; - case 1: - if (data[14] == 2) { - if (ui_ChannelNo == 0) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo ==0 ) */ - if (ui_ChannelNo == 1) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 64; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo ==1) */ - if (ui_ChannelNo == 2) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=128; */ - s_BoardInfos[dev->minor].i_Offset = 128; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo ==2 ) */ - if (ui_ChannelNo == 3) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=192; */ - s_BoardInfos[dev->minor].i_Offset = 192; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo ==3) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=0; */ - s_BoardInfos[dev->minor].i_ChannelNo = 0; - /* END JK 06.07.04: Management of sevrals boards */ - ui_ChannelNo = 0; - break; - } /* if(data[14]==2) */ - if (ui_ChannelNo >= 0 && ui_ChannelNo <= 1) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(ui_ChannelNo >=0 && ui_ChannelNo <=1) */ - if (ui_ChannelNo >= 2 && ui_ChannelNo <= 3) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=i_ChannelNo-2; */ - /* i_Offset=64; */ - s_BoardInfos[dev->minor].i_ChannelNo = - s_BoardInfos[dev->minor].i_ChannelNo - - 2; - s_BoardInfos[dev->minor].i_Offset = 64; - /* END JK 06.07.04: Management of sevrals boards */ - ui_ChannelNo = ui_ChannelNo - 2; - } /* if(ui_ChannelNo >=2 && ui_ChannelNo <=3) */ - if (ui_ChannelNo >= 4 && ui_ChannelNo <= 5) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=i_ChannelNo-4; */ - /* i_Offset=128; */ - s_BoardInfos[dev->minor].i_ChannelNo = - s_BoardInfos[dev->minor].i_ChannelNo - - 4; - s_BoardInfos[dev->minor].i_Offset = 128; - /* END JK 06.07.04: Management of sevrals boards */ - ui_ChannelNo = ui_ChannelNo - 4; - } /* if(ui_ChannelNo >=4 && ui_ChannelNo <=5) */ - if (ui_ChannelNo >= 6 && ui_ChannelNo <= 7) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_ChannelNo=i_ChannelNo-6; */ - /* i_Offset=192; */ - s_BoardInfos[dev->minor].i_ChannelNo = - s_BoardInfos[dev->minor].i_ChannelNo - - 6; - s_BoardInfos[dev->minor].i_Offset = 192; - /* END JK 06.07.04: Management of sevrals boards */ - ui_ChannelNo = ui_ChannelNo - 6; - } /* if(ui_ChannelNo >=6 && ui_ChannelNo <=7) */ - break; - - default: - printk("\n This selection of polarity does not exist\n"); - i_err++; - } /* switch(data[2]) */ - } /* if(data[12]==0 || data[12]==1) */ - else { - switch (data[11]) { - case 1: - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=0; */ - s_BoardInfos[dev->minor].i_Offset = 0; - /* END JK 06.07.04: Management of sevrals boards */ - break; - case 2: - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=64; */ - s_BoardInfos[dev->minor].i_Offset = 64; - /* END JK 06.07.04: Management of sevrals boards */ - break; - case 3: - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=128; */ - s_BoardInfos[dev->minor].i_Offset = 128; - /* END JK 06.07.04: Management of sevrals boards */ - break; - case 4: - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Offset=192; */ - s_BoardInfos[dev->minor].i_Offset = 192; - /* END JK 06.07.04: Management of sevrals boards */ - break; - default: - printk("\nError in module selection\n"); - i_err++; - } /* switch(data[11]) */ - } /* elseif(data[12]==0 || data[12]==1) */ - if (i_err) { - i_APCI3200_Reset(dev); - return -EINVAL; - } - /* if(i_ScanType!=1) */ - if (s_BoardInfos[dev->minor].i_ScanType != 1) { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Count=0; */ - /* i_Sum=0; */ - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(i_ScanType!=1) */ - - ul_Config = - data[1] | (data[2] << 6) | (data[5] << 7) | (data[3] << 8) | - (data[4] << 9); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* END JK 06.07.04: Management of sevrals boards */ - /*********************************/ - /* Write the channel to configure */ - /*********************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* outl(0 | ui_ChannelNo , devpriv->iobase+i_Offset + 0x4); */ - outl(0 | ui_ChannelNo, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x4); - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* END JK 06.07.04: Management of sevrals boards */ - /**************************/ - /* Reset the configuration */ - /**************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* outl(0 , devpriv->iobase+i_Offset + 0x0); */ - outl(0, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0); - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* END JK 06.07.04: Management of sevrals boards */ - - /***************************/ - /* Write the configuration */ - /***************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* outl(ul_Config , devpriv->iobase+i_Offset + 0x0); */ - outl(ul_Config, - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0); - /* END JK 06.07.04: Management of sevrals boards */ - - /***************************/ - /*Reset the calibration bit */ - /***************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ul_Temp = inl(devpriv->iobase+i_Offset + 12); */ - ul_Temp = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ - while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + - 12) >> 19) & 1) != 1) ; - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* outl((ul_Temp & 0xFFF9FFFF) , devpriv->iobase+.i_Offset + 12); */ - outl((ul_Temp & 0xFFF9FFFF), - devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); - /* END JK 06.07.04: Management of sevrals boards */ - - if (data[9] == 1) { - devpriv->tsk_Current = current; - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_InterruptFlag=1; */ - s_BoardInfos[dev->minor].i_InterruptFlag = 1; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(data[9]==1) */ - else { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_InterruptFlag=0; */ - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* else if(data[9]==1) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Initialised=1; */ - s_BoardInfos[dev->minor].i_Initialised = 1; - /* END JK 06.07.04: Management of sevrals boards */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_ScanType==1) */ - if (s_BoardInfos[dev->minor].i_ScanType == 1) - /* END JK 06.07.04: Management of sevrals boards */ - { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* i_Sum=i_Sum+1; */ - s_BoardInfos[dev->minor].i_Sum = - s_BoardInfos[dev->minor].i_Sum + 1; - /* END JK 06.07.04: Management of sevrals boards */ - - insn->unused[0] = 0; - i_APCI3200_ReadAnalogInput(dev, s, insn, &ui_Dummy); - } + data[1] = inl(devpriv->i_IobaseReserved) & 0xf; return insn->n; } -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ReadAnalogInput | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read value of the selected channel | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int ui_NoOfChannels : No Of Channels To read | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - | data[0] : Digital Value Of Input | - | data[1] : Calibration Offset Value | - | data[2] : Calibration Gain Value - | data[3] : CJC value - | data[4] : CJC offset value - | data[5] : CJC gain value - | Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - | data[6] : CJC current source from eeprom - | data[7] : Channel current source from eeprom - | data[8] : Channle gain factor from eeprom - | End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int apci3200_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int ui_DummyValue = 0; - int i_ConvertCJCCalibration; - int i = 0; - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_Initialised==0) */ - if (s_BoardInfos[dev->minor].i_Initialised == 0) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_APCI3200_Reset(dev); - return -EINVAL; - } /* if(i_Initialised==0); */ - -#ifdef PRINT_INFO - printk("\n insn->unused[0] = %i", insn->unused[0]); -#endif - - switch (insn->unused[0]) { - case 0: - - i_APCI3200_Read1AnalogInputChannel(dev, s, insn, - &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count+0]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev->minor]. - i_Count + 0] = ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - - /* Begin JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - i_APCI3200_GetChannelCalibrationValue(dev, - s_BoardInfos[dev->minor].ui_Channel_num, - &s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev->minor]. - i_Count + 6], - &s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev->minor]. - i_Count + 7], - &s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev->minor]. - i_Count + 8]); - -#ifdef PRINT_INFO - printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+6] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 6]); - - printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+7] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 7]); - - printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+8] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 8]); -#endif - - /* End JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) */ - if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2) - && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE) - && (s_BoardInfos[dev->minor].i_CJCAvailable == 1)) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_APCI3200_ReadCJCValue(dev, &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count + 3]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev-> - minor].i_Count + 3] = ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) */ - else { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count + 3]=0; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev-> - minor].i_Count + 3] = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* elseif((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) */ - if ((s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) - && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE)) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_APCI3200_ReadCalibrationOffsetValue(dev, - &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count + 1]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev-> - minor].i_Count + 1] = ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - i_APCI3200_ReadCalibrationGainValue(dev, - &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count + 2]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos[dev-> - minor].i_Count + 2] = ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)&& (i_CJCAvailable==1)) */ - if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2) - && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE) - && (s_BoardInfos[dev->minor].i_CJCAvailable == 1)) - /* END JK 06.07.04: Management of sevrals boards */ - { - /**********************************************************/ - /*Test if the Calibration channel must be read for the CJC */ - /**********************************************************/ - /**********************************/ - /*Test if the polarity is the same */ - /**********************************/ - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ - if (s_BoardInfos[dev->minor].i_CJCPolarity != - s_BoardInfos[dev->minor].i_ADDIDATAPolarity) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_ConvertCJCCalibration = 1; - } /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ - else { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_CJCGain==i_ADDIDATAGain) */ - if (s_BoardInfos[dev->minor].i_CJCGain == - s_BoardInfos[dev->minor].i_ADDIDATAGain) - /* END JK 06.07.04: Management of sevrals boards */ - { - i_ConvertCJCCalibration = 0; - } /* if(i_CJCGain==i_ADDIDATAGain) */ - else { - i_ConvertCJCCalibration = 1; - } /* elseif(i_CJCGain==i_ADDIDATAGain) */ - } /* elseif(i_CJCPolarity!=i_ADDIDATAPolarity) */ - if (i_ConvertCJCCalibration == 1) { - i_APCI3200_ReadCJCCalOffset(dev, - &ui_DummyValue); - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count+4]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos - [dev->minor].i_Count + 4] = - ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - - i_APCI3200_ReadCJCCalGain(dev, &ui_DummyValue); - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count+5]=ui_DummyValue; */ - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos - [dev->minor].i_Count + 5] = - ui_DummyValue; - /* END JK 06.07.04: Management of sevrals boards */ - } /* if(i_ConvertCJCCalibration==1) */ - else { - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* ui_InterruptChannelValue[i_Count+4]=0; */ - /* ui_InterruptChannelValue[i_Count+5]=0; */ - - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos - [dev->minor].i_Count + 4] = 0; - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[s_BoardInfos - [dev->minor].i_Count + 5] = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } /* elseif(i_ConvertCJCCalibration==1) */ - } /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) */ - - /* BEGIN JK 06.07.04: Management of sevrals boards */ - /* if(i_ScanType!=1) */ - if (s_BoardInfos[dev->minor].i_ScanType != 1) { - /* i_Count=0; */ - s_BoardInfos[dev->minor].i_Count = 0; - } /* if(i_ScanType!=1) */ - else { - /* i_Count=i_Count +6; */ - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count +6; */ - s_BoardInfos[dev->minor].i_Count = - s_BoardInfos[dev->minor].i_Count + 9; - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } /* else if(i_ScanType!=1) */ - - /* if((i_ScanType==1) &&(i_InterruptFlag==1)) */ - if ((s_BoardInfos[dev->minor].i_ScanType == 1) - && (s_BoardInfos[dev->minor].i_InterruptFlag == 1)) { - /* i_Count=i_Count-6; */ - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count-6; */ - s_BoardInfos[dev->minor].i_Count = - s_BoardInfos[dev->minor].i_Count - 9; - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } - /* if(i_ScanType==0) */ - if (s_BoardInfos[dev->minor].i_ScanType == 0) { - /* - data[0]= ui_InterruptChannelValue[0]; - data[1]= ui_InterruptChannelValue[1]; - data[2]= ui_InterruptChannelValue[2]; - data[3]= ui_InterruptChannelValue[3]; - data[4]= ui_InterruptChannelValue[4]; - data[5]= ui_InterruptChannelValue[5]; - */ -#ifdef PRINT_INFO - printk("\n data[0]= s_BoardInfos [dev->minor].ui_InterruptChannelValue[0];"); -#endif - data[0] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[0]; - data[1] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[1]; - data[2] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[2]; - data[3] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[3]; - data[4] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[4]; - data[5] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[5]; + struct addi_private *devpriv = dev->private; - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - /* printk("\n 0 - i_APCI3200_GetChannelCalibrationValue data [6] = %lu, data [7] = %lu, data [8] = %lu", data [6], data [7], data [8]); */ - i_APCI3200_GetChannelCalibrationValue(dev, - s_BoardInfos[dev->minor].ui_Channel_num, - &data[6], &data[7], &data[8]); - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - } - break; - case 1: + s->state = inl(devpriv->i_IobaseAddon) & 0xf; - for (i = 0; i < insn->n; i++) { - /* data[i]=ui_InterruptChannelValue[i]; */ - data[i] = - s_BoardInfos[dev->minor]. - ui_InterruptChannelValue[i]; - } + if (comedi_dio_update_state(s, data)) + outl(s->state, devpriv->i_IobaseAddon); - /* i_Count=0; */ - /* i_Sum=0; */ - /* if(i_ScanType==1) */ - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - if (s_BoardInfos[dev->minor].i_ScanType == 1) { - /* i_Initialised=0; */ - /* i_InterruptFlag=0; */ - s_BoardInfos[dev->minor].i_Initialised = 0; - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - /* END JK 06.07.04: Management of sevrals boards */ - } - break; - default: - printk("\nThe parameters passed are in error\n"); - i_APCI3200_Reset(dev); - return -EINVAL; - } /* switch(insn->unused[0]) */ + data[1] = s->state; return insn->n; } -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_Read1AnalogInputChannel | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read value of the selected channel | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int ui_NoOfChannel : Channel No to read | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - | data[0] : Digital Value read | - | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_Read1AnalogInputChannel(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) +static int i_APCI3200_Read1AnalogInputChannel(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_EOC = 0; unsigned int ui_ChannelNo = 0; unsigned int ui_CommandRegister = 0; @@ -1749,28 +742,10 @@ int i_APCI3200_Read1AnalogInputChannel(struct comedi_device *dev, return 0; } -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ReadCalibrationOffsetValue | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read calibration offset value of the selected channel| - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - | data[0] : Calibration offset Value | - | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, unsigned int *data) +static int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_Temp = 0, ui_EOC = 0; unsigned int ui_CommandRegister = 0; @@ -1885,28 +860,10 @@ int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, unsigned in return 0; } -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ReadCalibrationGainValue | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read calibration gain value of the selected channel | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - | data[0] : Calibration gain Value Of Input | - | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, unsigned int *data) +static int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_EOC = 0; int ui_CommandRegister = 0; @@ -2020,29 +977,10 @@ int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, unsigned int return 0; } -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ReadCJCValue | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read CJC value of the selected channel | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - | data[0] : CJC Value | - | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ - -int i_APCI3200_ReadCJCValue(struct comedi_device *dev, unsigned int *data) +static int i_APCI3200_ReadCJCValue(struct comedi_device *dev, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_EOC = 0; int ui_CommandRegister = 0; @@ -2140,30 +1078,13 @@ int i_APCI3200_ReadCJCValue(struct comedi_device *dev, unsigned int *data) return 0; } -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ReadCJCCalOffset | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read CJC calibration offset value of the selected channel - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - | data[0] : CJC calibration offset Value - | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_ReadCJCCalOffset(struct comedi_device *dev, unsigned int *data) +static int i_APCI3200_ReadCJCCalOffset(struct comedi_device *dev, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_EOC = 0; int ui_CommandRegister = 0; + /*******************************************/ /*Read calibration offset value for the CJC */ /*******************************************/ @@ -2255,31 +1176,13 @@ int i_APCI3200_ReadCJCCalOffset(struct comedi_device *dev, unsigned int *data) return 0; } -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_ReadCJCGainValue | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Read CJC calibration gain value - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | unsigned int ui_NoOfChannels : No Of Channels To read | - | unsigned int *data : Data Pointer to read status | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - | data[0] : CJC calibration gain value - | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, unsigned int *data) +static int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_EOC = 0; int ui_CommandRegister = 0; + /*******************************/ /* Set the convert timing unit */ /*******************************/ @@ -2365,52 +1268,851 @@ int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, unsigned int *data) return 0; } +static int apci3200_reset(struct comedi_device *dev) +{ + struct addi_private *devpriv = dev->private; + int i_Temp; + unsigned int dw_Dummy; + + /* i_InterruptFlag=0; */ + /* i_Initialised==0; */ + /* i_Count=0; */ + /* i_Sum=0; */ + + s_BoardInfos[dev->minor].i_InterruptFlag = 0; + s_BoardInfos[dev->minor].i_Initialised = 0; + s_BoardInfos[dev->minor].i_Count = 0; + s_BoardInfos[dev->minor].i_Sum = 0; + s_BoardInfos[dev->minor].b_StructInitialized = 0; + + outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); + + /* Enable the interrupt for the controller */ + dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); + outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); + outl(0, devpriv->i_IobaseAddon); /* Resets the output */ + /***************/ + /*Empty the buffer */ + /**************/ + for (i_Temp = 0; i_Temp <= 95; i_Temp++) { + /* ui_InterruptChannelValue[i_Temp]=0; */ + s_BoardInfos[dev->minor].ui_InterruptChannelValue[i_Temp] = 0; + } /* for(i_Temp=0;i_Temp<=95;i_Temp++) */ + /*****************************/ + /*Reset the START and IRQ bit */ + /*****************************/ + for (i_Temp = 0; i_Temp <= 192;) { + while (((inl(devpriv->iobase + i_Temp + 12) >> 19) & 1) != 1) ; + outl(0, devpriv->iobase + i_Temp + 8); + i_Temp = i_Temp + 64; + } /* for(i_Temp=0;i_Temp<=192;i_Temp+64) */ + return 0; +} + /* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_InsnBits_AnalogInput_Test | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Tests the Selected Anlog Input Channel | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | struct comedi_subdevice *s : Subdevice Pointer | - | struct comedi_insn *insn : Insn Structure Pointer | - | unsigned int *data : Data Pointer contains | - | configuration parameters as below | - | - | - | data[0] : 0 TestAnalogInputShortCircuit - | 1 TestAnalogInputConnection | - - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - | data[0] : Digital value obtained | - | data[1] : calibration offset | - | data[2] : calibration gain | - | | - | | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ + * Read value of the selected channel + * + * data[0] : Digital Value Of Input + * data[1] : Calibration Offset Value + * data[2] : Calibration Gain Value + * data[3] : CJC value + * data[4] : CJC offset value + * data[5] : CJC gain value + * data[6] : CJC current source from eeprom + * data[7] : Channel current source from eeprom + * data[8] : Channle gain factor from eeprom + */ +static int apci3200_ai_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int ui_DummyValue = 0; + int i_ConvertCJCCalibration; + int i = 0; + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_Initialised==0) */ + if (s_BoardInfos[dev->minor].i_Initialised == 0) + /* END JK 06.07.04: Management of sevrals boards */ + { + apci3200_reset(dev); + return -EINVAL; + } /* if(i_Initialised==0); */ + +#ifdef PRINT_INFO + printk("\n insn->unused[0] = %i", insn->unused[0]); +#endif + + switch (insn->unused[0]) { + case 0: + + i_APCI3200_Read1AnalogInputChannel(dev, s, insn, + &ui_DummyValue); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count+0]=ui_DummyValue; */ + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos[dev->minor]. + i_Count + 0] = ui_DummyValue; + /* END JK 06.07.04: Management of sevrals boards */ + + /* Begin JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + i_APCI3200_GetChannelCalibrationValue(dev, + s_BoardInfos[dev->minor].ui_Channel_num, + &s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos[dev->minor]. + i_Count + 6], + &s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos[dev->minor]. + i_Count + 7], + &s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos[dev->minor]. + i_Count + 8]); + +#ifdef PRINT_INFO + printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+6] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 6]); + + printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+7] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 7]); + + printk("\n s_BoardInfos [dev->minor].ui_InterruptChannelValue[s_BoardInfos [dev->minor].i_Count+8] = %lu", s_BoardInfos[dev->minor].ui_InterruptChannelValue[s_BoardInfos[dev->minor].i_Count + 8]); +#endif + + /* End JK 25.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) */ + if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2) + && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE) + && (s_BoardInfos[dev->minor].i_CJCAvailable == 1)) + /* END JK 06.07.04: Management of sevrals boards */ + { + i_APCI3200_ReadCJCValue(dev, &ui_DummyValue); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count + 3]=ui_DummyValue; */ + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos[dev-> + minor].i_Count + 3] = ui_DummyValue; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) */ + else { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count + 3]=0; */ + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos[dev-> + minor].i_Count + 3] = 0; + /* END JK 06.07.04: Management of sevrals boards */ + } /* elseif((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE) && (i_CJCAvailable==1)) */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) */ + if ((s_BoardInfos[dev->minor].i_AutoCalibration == FALSE) + && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE)) + /* END JK 06.07.04: Management of sevrals boards */ + { + i_APCI3200_ReadCalibrationOffsetValue(dev, + &ui_DummyValue); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count + 1]=ui_DummyValue; */ + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos[dev-> + minor].i_Count + 1] = ui_DummyValue; + /* END JK 06.07.04: Management of sevrals boards */ + i_APCI3200_ReadCalibrationGainValue(dev, + &ui_DummyValue); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count + 2]=ui_DummyValue; */ + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos[dev-> + minor].i_Count + 2] = ui_DummyValue; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if (( i_AutoCalibration == FALSE) && (i_InterruptFlag == FALSE)) */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)&& (i_CJCAvailable==1)) */ + if ((s_BoardInfos[dev->minor].i_ADDIDATAType == 2) + && (s_BoardInfos[dev->minor].i_InterruptFlag == FALSE) + && (s_BoardInfos[dev->minor].i_CJCAvailable == 1)) + /* END JK 06.07.04: Management of sevrals boards */ + { + /**********************************************************/ + /*Test if the Calibration channel must be read for the CJC */ + /**********************************************************/ + /**********************************/ + /*Test if the polarity is the same */ + /**********************************/ + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ + if (s_BoardInfos[dev->minor].i_CJCPolarity != + s_BoardInfos[dev->minor].i_ADDIDATAPolarity) + /* END JK 06.07.04: Management of sevrals boards */ + { + i_ConvertCJCCalibration = 1; + } /* if(i_CJCPolarity!=i_ADDIDATAPolarity) */ + else { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_CJCGain==i_ADDIDATAGain) */ + if (s_BoardInfos[dev->minor].i_CJCGain == + s_BoardInfos[dev->minor].i_ADDIDATAGain) + /* END JK 06.07.04: Management of sevrals boards */ + { + i_ConvertCJCCalibration = 0; + } /* if(i_CJCGain==i_ADDIDATAGain) */ + else { + i_ConvertCJCCalibration = 1; + } /* elseif(i_CJCGain==i_ADDIDATAGain) */ + } /* elseif(i_CJCPolarity!=i_ADDIDATAPolarity) */ + if (i_ConvertCJCCalibration == 1) { + i_APCI3200_ReadCJCCalOffset(dev, + &ui_DummyValue); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count+4]=ui_DummyValue; */ + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos + [dev->minor].i_Count + 4] = + ui_DummyValue; + /* END JK 06.07.04: Management of sevrals boards */ + + i_APCI3200_ReadCJCCalGain(dev, &ui_DummyValue); + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count+5]=ui_DummyValue; */ + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos + [dev->minor].i_Count + 5] = + ui_DummyValue; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(i_ConvertCJCCalibration==1) */ + else { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ui_InterruptChannelValue[i_Count+4]=0; */ + /* ui_InterruptChannelValue[i_Count+5]=0; */ + + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos + [dev->minor].i_Count + 4] = 0; + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[s_BoardInfos + [dev->minor].i_Count + 5] = 0; + /* END JK 06.07.04: Management of sevrals boards */ + } /* elseif(i_ConvertCJCCalibration==1) */ + } /* if((i_ADDIDATAType==2) && (i_InterruptFlag == FALSE)) */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_ScanType!=1) */ + if (s_BoardInfos[dev->minor].i_ScanType != 1) { + /* i_Count=0; */ + s_BoardInfos[dev->minor].i_Count = 0; + } /* if(i_ScanType!=1) */ + else { + /* i_Count=i_Count +6; */ + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count +6; */ + s_BoardInfos[dev->minor].i_Count = + s_BoardInfos[dev->minor].i_Count + 9; + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + } /* else if(i_ScanType!=1) */ + + /* if((i_ScanType==1) &&(i_InterruptFlag==1)) */ + if ((s_BoardInfos[dev->minor].i_ScanType == 1) + && (s_BoardInfos[dev->minor].i_InterruptFlag == 1)) { + /* i_Count=i_Count-6; */ + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + /* s_BoardInfos [dev->minor].i_Count=s_BoardInfos [dev->minor].i_Count-6; */ + s_BoardInfos[dev->minor].i_Count = + s_BoardInfos[dev->minor].i_Count - 9; + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + } + /* if(i_ScanType==0) */ + if (s_BoardInfos[dev->minor].i_ScanType == 0) { + /* + data[0]= ui_InterruptChannelValue[0]; + data[1]= ui_InterruptChannelValue[1]; + data[2]= ui_InterruptChannelValue[2]; + data[3]= ui_InterruptChannelValue[3]; + data[4]= ui_InterruptChannelValue[4]; + data[5]= ui_InterruptChannelValue[5]; + */ +#ifdef PRINT_INFO + printk("\n data[0]= s_BoardInfos [dev->minor].ui_InterruptChannelValue[0];"); +#endif + data[0] = + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[0]; + data[1] = + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[1]; + data[2] = + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[2]; + data[3] = + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[3]; + data[4] = + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[4]; + data[5] = + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[5]; + + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + /* printk("\n 0 - i_APCI3200_GetChannelCalibrationValue data [6] = %lu, data [7] = %lu, data [8] = %lu", data [6], data [7], data [8]); */ + i_APCI3200_GetChannelCalibrationValue(dev, + s_BoardInfos[dev->minor].ui_Channel_num, + &data[6], &data[7], &data[8]); + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + } + break; + case 1: + + for (i = 0; i < insn->n; i++) { + /* data[i]=ui_InterruptChannelValue[i]; */ + data[i] = + s_BoardInfos[dev->minor]. + ui_InterruptChannelValue[i]; + } + + /* i_Count=0; */ + /* i_Sum=0; */ + /* if(i_ScanType==1) */ + s_BoardInfos[dev->minor].i_Count = 0; + s_BoardInfos[dev->minor].i_Sum = 0; + if (s_BoardInfos[dev->minor].i_ScanType == 1) { + /* i_Initialised=0; */ + /* i_InterruptFlag=0; */ + s_BoardInfos[dev->minor].i_Initialised = 0; + s_BoardInfos[dev->minor].i_InterruptFlag = 0; + /* END JK 06.07.04: Management of sevrals boards */ + } + break; + default: + printk("\nThe parameters passed are in error\n"); + apci3200_reset(dev); + return -EINVAL; + } /* switch(insn->unused[0]) */ + + return insn->n; +} + +/* + * Configures The Analog Input Subdevice + * + * data[0] = 0 Normal AI + * = 1 RTD + * = 2 THERMOCOUPLE + * data[1] = Gain To Use + * data[2] = 0 Bipolar + * = 1 Unipolar + * data[3] = Offset Range + * data[4] = 0 DC Coupling + * = 1 AC Coupling + * data[5] = 0 Single + * = 1 Differential + * data[6] = TimerReloadValue + * data[7] = ConvertingTimeUnit + * data[8] = 0 Analog voltage measurement + * = 1 Resistance measurement + * = 2 Temperature measurement + * data[9] = 0 Interrupt Disable + * = 1 INterrupt Enable + * data[10] = Type of Thermocouple + * data[11] = single channel Module Number + * data[12] = 0 Single Read + * = 1 Read more channel + * = 2 Single scan + * = 3 Continuous Scan + * data[13] = Number of channels to read + * data[14] = 0 RTD not used + * = 1 RTD 2 wire connection + * = 2 RTD 3 wire connection + * = 3 RTD 4 wire connection + */ +static int apci3200_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_private *devpriv = dev->private; + unsigned int ul_Config = 0, ul_Temp = 0; + unsigned int ui_ChannelNo = 0; + unsigned int ui_Dummy = 0; + int i_err = 0; + + /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + +#ifdef PRINT_INFO + int i = 0, i2 = 0; +#endif + /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* Initialize the structure */ + if (s_BoardInfos[dev->minor].b_StructInitialized != 1) { + s_BoardInfos[dev->minor].i_CJCAvailable = 1; + s_BoardInfos[dev->minor].i_CJCPolarity = 0; + s_BoardInfos[dev->minor].i_CJCGain = 2; /* changed from 0 to 2 */ + s_BoardInfos[dev->minor].i_InterruptFlag = 0; + s_BoardInfos[dev->minor].i_AutoCalibration = 0; /* : auto calibration */ + s_BoardInfos[dev->minor].i_ChannelCount = 0; + s_BoardInfos[dev->minor].i_Sum = 0; + s_BoardInfos[dev->minor].ui_Channel_num = 0; + s_BoardInfos[dev->minor].i_Count = 0; + s_BoardInfos[dev->minor].i_Initialised = 0; + s_BoardInfos[dev->minor].b_StructInitialized = 1; + + /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + s_BoardInfos[dev->minor].i_ConnectionType = 0; + /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + + /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + memset(s_BoardInfos[dev->minor].s_Module, 0, + sizeof(s_BoardInfos[dev->minor].s_Module[MAX_MODULE])); + + v_GetAPCI3200EepromCalibrationValue(devpriv->i_IobaseAmcc, + &s_BoardInfos[dev->minor]); + +#ifdef PRINT_INFO + for (i = 0; i < MAX_MODULE; i++) { + printk("\n s_Module[%i].ul_CurrentSourceCJC = %lu", i, + s_BoardInfos[dev->minor].s_Module[i]. + ul_CurrentSourceCJC); + + for (i2 = 0; i2 < 5; i2++) { + printk("\n s_Module[%i].ul_CurrentSource [%i] = %lu", i, i2, s_BoardInfos[dev->minor].s_Module[i].ul_CurrentSource[i2]); + } + + for (i2 = 0; i2 < 8; i2++) { + printk("\n s_Module[%i].ul_GainFactor [%i] = %lu", i, i2, s_BoardInfos[dev->minor].s_Module[i].ul_GainFactor[i2]); + } + + for (i2 = 0; i2 < 8; i2++) { + printk("\n s_Module[%i].w_GainValue [%i] = %u", + i, i2, + s_BoardInfos[dev->minor].s_Module[i]. + w_GainValue[i2]); + } + } +#endif + /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + } + + if (data[0] != 0 && data[0] != 1 && data[0] != 2) { + printk("\nThe selection of acquisition type is in error\n"); + i_err++; + } /* if(data[0]!=0 && data[0]!=1 && data[0]!=2) */ + if (data[0] == 1) { + if (data[14] != 0 && data[14] != 1 && data[14] != 2 + && data[14] != 4) { + printk("\n Error in selection of RTD connection type\n"); + i_err++; + } /* if(data[14]!=0 && data[14]!=1 && data[14]!=2 && data[14]!=4) */ + } /* if(data[0]==1 ) */ + if (data[1] < 0 || data[1] > 7) { + printk("\nThe selection of gain is in error\n"); + i_err++; + } /* if(data[1]<0 || data[1]>7) */ + if (data[2] != 0 && data[2] != 1) { + printk("\nThe selection of polarity is in error\n"); + i_err++; + } /* if(data[2]!=0 && data[2]!=1) */ + if (data[3] != 0) { + printk("\nThe selection of offset range is in error\n"); + i_err++; + } /* if(data[3]!=0) */ + if (data[4] != 0 && data[4] != 1) { + printk("\nThe selection of coupling is in error\n"); + i_err++; + } /* if(data[4]!=0 && data[4]!=1) */ + if (data[5] != 0 && data[5] != 1) { + printk("\nThe selection of single/differential mode is in error\n"); + i_err++; + } /* if(data[5]!=0 && data[5]!=1) */ + if (data[8] != 0 && data[8] != 1 && data[2] != 2) { + printk("\nError in selection of functionality\n"); + } /* if(data[8]!=0 && data[8]!=1 && data[2]!=2) */ + if (data[12] == 0 || data[12] == 1) { + if (data[6] != 20 && data[6] != 40 && data[6] != 80 + && data[6] != 160) { + printk("\nThe selection of conversion time reload value is in error\n"); + i_err++; + } /* if (data[6]!=20 && data[6]!=40 && data[6]!=80 && data[6]!=160 ) */ + if (data[7] != 2) { + printk("\nThe selection of conversion time unit is in error\n"); + i_err++; + } /* if(data[7]!=2) */ + } + if (data[9] != 0 && data[9] != 1) { + printk("\nThe selection of interrupt enable is in error\n"); + i_err++; + } /* if(data[9]!=0 && data[9]!=1) */ + if (data[11] < 0 || data[11] > 4) { + printk("\nThe selection of module is in error\n"); + i_err++; + } /* if(data[11] <0 || data[11]>1) */ + if (data[12] < 0 || data[12] > 3) { + printk("\nThe selection of singlechannel/scan selection is in error\n"); + i_err++; + } /* if(data[12] < 0 || data[12]> 3) */ + if (data[13] < 0 || data[13] > 16) { + printk("\nThe selection of number of channels is in error\n"); + i_err++; + } /* if(data[13] <0 ||data[13] >15) */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* + i_ChannelCount=data[13]; + i_ScanType=data[12]; + i_ADDIDATAPolarity = data[2]; + i_ADDIDATAGain=data[1]; + i_ADDIDATAConversionTime=data[6]; + i_ADDIDATAConversionTimeUnit=data[7]; + i_ADDIDATAType=data[0]; + */ + + /* Save acquisition configuration for the actual board */ + s_BoardInfos[dev->minor].i_ChannelCount = data[13]; + s_BoardInfos[dev->minor].i_ScanType = data[12]; + s_BoardInfos[dev->minor].i_ADDIDATAPolarity = data[2]; + s_BoardInfos[dev->minor].i_ADDIDATAGain = data[1]; + s_BoardInfos[dev->minor].i_ADDIDATAConversionTime = data[6]; + s_BoardInfos[dev->minor].i_ADDIDATAConversionTimeUnit = data[7]; + s_BoardInfos[dev->minor].i_ADDIDATAType = data[0]; + /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + s_BoardInfos[dev->minor].i_ConnectionType = data[5]; + /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* END JK 06.07.04: Management of sevrals boards */ + + /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + memset(s_BoardInfos[dev->minor].ui_ScanValueArray, 0, (7 + 12) * sizeof(unsigned int)); /* 7 is the maximal number of channels */ + /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + + /* BEGIN JK 02.07.04 : This while can't be do, it block the process when using severals boards */ + /* while(i_InterruptFlag==1) */ + while (s_BoardInfos[dev->minor].i_InterruptFlag == 1) { +#ifndef MSXBOX + udelay(1); +#else + /* In the case where the driver is compiled for the MSX-Box */ + /* we used a printk to have a little delay because udelay */ + /* seems to be broken under the MSX-Box. */ + /* This solution hat to be studied. */ + printk(""); +#endif + } + /* END JK 02.07.04 : This while can't be do, it block the process when using severals boards */ + + ui_ChannelNo = CR_CHAN(insn->chanspec); /* get the channel */ + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=ui_ChannelNo; */ + /* ui_Channel_num =ui_ChannelNo; */ + + s_BoardInfos[dev->minor].i_ChannelNo = ui_ChannelNo; + s_BoardInfos[dev->minor].ui_Channel_num = ui_ChannelNo; + + /* END JK 06.07.04: Management of sevrals boards */ + + if (data[5] == 0) { + if (ui_ChannelNo < 0 || ui_ChannelNo > 15) { + printk("\nThe Selection of the channel is in error\n"); + i_err++; + } /* if(ui_ChannelNo<0 || ui_ChannelNo>15) */ + } /* if(data[5]==0) */ + else { + if (data[14] == 2) { + if (ui_ChannelNo < 0 || ui_ChannelNo > 3) { + printk("\nThe Selection of the channel is in error\n"); + i_err++; + } /* if(ui_ChannelNo<0 || ui_ChannelNo>3) */ + } /* if(data[14]==2) */ + else { + if (ui_ChannelNo < 0 || ui_ChannelNo > 7) { + printk("\nThe Selection of the channel is in error\n"); + i_err++; + } /* if(ui_ChannelNo<0 || ui_ChannelNo>7) */ + } /* elseif(data[14]==2) */ + } /* elseif(data[5]==0) */ + if (data[12] == 0 || data[12] == 1) { + switch (data[5]) { + case 0: + if (ui_ChannelNo >= 0 && ui_ChannelNo <= 3) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ + s_BoardInfos[dev->minor].i_Offset = 0; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=0 && ui_ChannelNo <=3) */ + if (ui_ChannelNo >= 4 && ui_ChannelNo <= 7) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=64; */ + s_BoardInfos[dev->minor].i_Offset = 64; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=4 && ui_ChannelNo <=7) */ + if (ui_ChannelNo >= 8 && ui_ChannelNo <= 11) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=128; */ + s_BoardInfos[dev->minor].i_Offset = 128; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=8 && ui_ChannelNo <=11) */ + if (ui_ChannelNo >= 12 && ui_ChannelNo <= 15) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=192; */ + s_BoardInfos[dev->minor].i_Offset = 192; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=12 && ui_ChannelNo <=15) */ + break; + case 1: + if (data[14] == 2) { + if (ui_ChannelNo == 0) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ + s_BoardInfos[dev->minor].i_Offset = 0; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo ==0 ) */ + if (ui_ChannelNo == 1) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ + s_BoardInfos[dev->minor].i_Offset = 64; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo ==1) */ + if (ui_ChannelNo == 2) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=128; */ + s_BoardInfos[dev->minor].i_Offset = 128; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo ==2 ) */ + if (ui_ChannelNo == 3) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=192; */ + s_BoardInfos[dev->minor].i_Offset = 192; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo ==3) */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=0; */ + s_BoardInfos[dev->minor].i_ChannelNo = 0; + /* END JK 06.07.04: Management of sevrals boards */ + ui_ChannelNo = 0; + break; + } /* if(data[14]==2) */ + if (ui_ChannelNo >= 0 && ui_ChannelNo <= 1) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ + s_BoardInfos[dev->minor].i_Offset = 0; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(ui_ChannelNo >=0 && ui_ChannelNo <=1) */ + if (ui_ChannelNo >= 2 && ui_ChannelNo <= 3) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=i_ChannelNo-2; */ + /* i_Offset=64; */ + s_BoardInfos[dev->minor].i_ChannelNo = + s_BoardInfos[dev->minor].i_ChannelNo - + 2; + s_BoardInfos[dev->minor].i_Offset = 64; + /* END JK 06.07.04: Management of sevrals boards */ + ui_ChannelNo = ui_ChannelNo - 2; + } /* if(ui_ChannelNo >=2 && ui_ChannelNo <=3) */ + if (ui_ChannelNo >= 4 && ui_ChannelNo <= 5) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=i_ChannelNo-4; */ + /* i_Offset=128; */ + s_BoardInfos[dev->minor].i_ChannelNo = + s_BoardInfos[dev->minor].i_ChannelNo - + 4; + s_BoardInfos[dev->minor].i_Offset = 128; + /* END JK 06.07.04: Management of sevrals boards */ + ui_ChannelNo = ui_ChannelNo - 4; + } /* if(ui_ChannelNo >=4 && ui_ChannelNo <=5) */ + if (ui_ChannelNo >= 6 && ui_ChannelNo <= 7) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_ChannelNo=i_ChannelNo-6; */ + /* i_Offset=192; */ + s_BoardInfos[dev->minor].i_ChannelNo = + s_BoardInfos[dev->minor].i_ChannelNo - + 6; + s_BoardInfos[dev->minor].i_Offset = 192; + /* END JK 06.07.04: Management of sevrals boards */ + ui_ChannelNo = ui_ChannelNo - 6; + } /* if(ui_ChannelNo >=6 && ui_ChannelNo <=7) */ + break; + + default: + printk("\n This selection of polarity does not exist\n"); + i_err++; + } /* switch(data[2]) */ + } /* if(data[12]==0 || data[12]==1) */ + else { + switch (data[11]) { + case 1: + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=0; */ + s_BoardInfos[dev->minor].i_Offset = 0; + /* END JK 06.07.04: Management of sevrals boards */ + break; + case 2: + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=64; */ + s_BoardInfos[dev->minor].i_Offset = 64; + /* END JK 06.07.04: Management of sevrals boards */ + break; + case 3: + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=128; */ + s_BoardInfos[dev->minor].i_Offset = 128; + /* END JK 06.07.04: Management of sevrals boards */ + break; + case 4: + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Offset=192; */ + s_BoardInfos[dev->minor].i_Offset = 192; + /* END JK 06.07.04: Management of sevrals boards */ + break; + default: + printk("\nError in module selection\n"); + i_err++; + } /* switch(data[11]) */ + } /* elseif(data[12]==0 || data[12]==1) */ + if (i_err) { + apci3200_reset(dev); + return -EINVAL; + } + /* if(i_ScanType!=1) */ + if (s_BoardInfos[dev->minor].i_ScanType != 1) { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Count=0; */ + /* i_Sum=0; */ + s_BoardInfos[dev->minor].i_Count = 0; + s_BoardInfos[dev->minor].i_Sum = 0; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(i_ScanType!=1) */ + + ul_Config = + data[1] | (data[2] << 6) | (data[5] << 7) | (data[3] << 8) | + (data[4] << 9); + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ + while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + + 12) >> 19) & 1) != 1) ; + /* END JK 06.07.04: Management of sevrals boards */ + /*********************************/ + /* Write the channel to configure */ + /*********************************/ + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* outl(0 | ui_ChannelNo , devpriv->iobase+i_Offset + 0x4); */ + outl(0 | ui_ChannelNo, + devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x4); + /* END JK 06.07.04: Management of sevrals boards */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ + while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + + 12) >> 19) & 1) != 1) ; + /* END JK 06.07.04: Management of sevrals boards */ + /**************************/ + /* Reset the configuration */ + /**************************/ + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* outl(0 , devpriv->iobase+i_Offset + 0x0); */ + outl(0, devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0); + /* END JK 06.07.04: Management of sevrals boards */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ + while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + + 12) >> 19) & 1) != 1) ; + /* END JK 06.07.04: Management of sevrals boards */ + + /***************************/ + /* Write the configuration */ + /***************************/ + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* outl(ul_Config , devpriv->iobase+i_Offset + 0x0); */ + outl(ul_Config, + devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 0x0); + /* END JK 06.07.04: Management of sevrals boards */ + + /***************************/ + /*Reset the calibration bit */ + /***************************/ + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* ul_Temp = inl(devpriv->iobase+i_Offset + 12); */ + ul_Temp = inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); + /* END JK 06.07.04: Management of sevrals boards */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* while (((inl(devpriv->iobase+i_Offset+12)>>19) & 1) != 1); */ + while (((inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + + 12) >> 19) & 1) != 1) ; + /* END JK 06.07.04: Management of sevrals boards */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* outl((ul_Temp & 0xFFF9FFFF) , devpriv->iobase+.i_Offset + 12); */ + outl((ul_Temp & 0xFFF9FFFF), + devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 12); + /* END JK 06.07.04: Management of sevrals boards */ + + if (data[9] == 1) { + devpriv->tsk_Current = current; + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_InterruptFlag=1; */ + s_BoardInfos[dev->minor].i_InterruptFlag = 1; + /* END JK 06.07.04: Management of sevrals boards */ + } /* if(data[9]==1) */ + else { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_InterruptFlag=0; */ + s_BoardInfos[dev->minor].i_InterruptFlag = 0; + /* END JK 06.07.04: Management of sevrals boards */ + } /* else if(data[9]==1) */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Initialised=1; */ + s_BoardInfos[dev->minor].i_Initialised = 1; + /* END JK 06.07.04: Management of sevrals boards */ + + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* if(i_ScanType==1) */ + if (s_BoardInfos[dev->minor].i_ScanType == 1) + /* END JK 06.07.04: Management of sevrals boards */ + { + /* BEGIN JK 06.07.04: Management of sevrals boards */ + /* i_Sum=i_Sum+1; */ + s_BoardInfos[dev->minor].i_Sum = + s_BoardInfos[dev->minor].i_Sum + 1; + /* END JK 06.07.04: Management of sevrals boards */ + + insn->unused[0] = 0; + apci3200_ai_read(dev, s, insn, &ui_Dummy); + } + + return insn->n; +} -int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) +/* + * Tests the Selected Anlog Input Channel + * + * data[0] = 0 TestAnalogInputShortCircuit + * = 1 TestAnalogInputConnection + * + * data[0] : Digital value obtained + * data[1] : calibration offset + * data[2] : calibration gain + */ +static int apci3200_ai_bits_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; int i_Temp; /* ,i_TimeUnit; */ + /* if(i_Initialised==0) */ if (s_BoardInfos[dev->minor].i_Initialised == 0) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(i_Initialised==0); */ if (data[0] != 0 && data[0] != 1) { printk("\nError in selection of functionality\n"); - i_APCI3200_Reset(dev); + apci3200_reset(dev); return -EINVAL; } /* if(data[0]!=0 && data[0]!=1) */ @@ -2500,142 +2202,87 @@ int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, return insn->n; } -/* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_InsnWriteReleaseAnalogInput | - | (struct comedi_device *dev,struct comedi_subdevice *s, | - | struct comedi_insn *insn,unsigned int *data) | - +----------------------------------------------------------------------------+ - | Task : Resets the channels | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev : Driver handle | - | struct comedi_subdevice *s : Subdevice Pointer | - | struct comedi_insn *insn : Insn Structure Pointer | - | unsigned int *data : Data Pointer - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ - -int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) +static int apci3200_ai_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return insn->n; } -/* - +----------------------------------------------------------------------------+ - | Function name :int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev| - | ,struct comedi_subdevice *s,struct comedi_cmd *cmd) | - | | - +----------------------------------------------------------------------------+ - | Task : Test validity for a command for cyclic anlog input | - | acquisition | - | | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev | - | struct comedi_subdevice *s | - | struct comedi_cmd *cmd | - | | - | - | | - | | - | | - +----------------------------------------------------------------------------+ - | Return Value :0 | - | | - +----------------------------------------------------------------------------+ -*/ - -int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int apci3200_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; - int tmp; /* divisor1,divisor2; */ unsigned int ui_ConvertTime = 0; unsigned int ui_ConvertTimeBase = 0; unsigned int ui_DelayTime = 0; unsigned int ui_DelayTimeBase = 0; - int i_Triggermode = 0; - int i_TriggerEdge = 0; int i_NbrOfChannel = 0; int i_Cpt = 0; double d_ConversionTimeForAllChannels = 0.0; double d_SCANTimeNewUnit = 0.0; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - /* if(i_InterruptFlag==0) */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { - err++; - /* printk("\nThe interrupt should be enabled\n"); */ - } + unsigned int arg; + + /* 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); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) + err |= -EINVAL; + if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 1; } - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) { - err++; - } - if (cmd->start_src == TRIG_EXT) { - i_TriggerEdge = cmd->start_arg & 0xFFFF; - i_Triggermode = cmd->start_arg >> 16; - if (i_TriggerEdge < 1 || i_TriggerEdge > 3) { - err++; - printk("\nThe trigger edge selection is in error\n"); - } - if (i_Triggermode != 2) { - err++; - printk("\nThe trigger mode selection is in error\n"); - } - } + /* Step 2a : make sure trigger sources are unique */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; + 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->stop_src); - if (cmd->convert_src != TRIG_TIMER) - err++; + /* Step 2b : and mutually compatible */ - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; + if (err) { + apci3200_reset(dev); + return 2; } - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* Step 3: check if arguments are trivially valid */ - if (err) { - i_APCI3200_Reset(dev); - return 2; + switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* validate the trigger edge selection */ + arg = cmd->start_arg & 0xffff; + if (arg < 1 || arg > 3) { + cmd->start_arg &= ~0xffff; + cmd->start_arg |= 1; + err |= -EINVAL; + } + /* validate the trigger mode selection */ + arg = cmd->start_arg >> 16; + if (arg != 2) { + cmd->start_arg &= ~(0xffff << 16); + cmd->start_arg |= (2 << 16); + err |= -EINVAL; + } + break; } + + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + /* i_FirstChannel=cmd->chanlist[0]; */ s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0]; /* i_LastChannel=cmd->chanlist[1]; */ @@ -2674,7 +2321,7 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s printk("\nThe Delay time value is in error\n"); } if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 3; } fpu_begin(); @@ -2732,34 +2379,19 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s } /* else if(cmd->scan_begin_src==TRIG_FOLLOW) */ if (err) { - i_APCI3200_Reset(dev); + apci3200_reset(dev); return 4; } return 0; } -/* - +----------------------------------------------------------------------------+ - | Function name :int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev,| - | struct comedi_subdevice *s)| - | | - +----------------------------------------------------------------------------+ - | Task : Stop the acquisition | - | | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev | - | struct comedi_subdevice *s | - | | - +----------------------------------------------------------------------------+ - | Return Value :0 | - | | - +----------------------------------------------------------------------------+ -*/ - -int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s) +static int apci3200_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { + struct addi_private *devpriv = dev->private; unsigned int ui_Configuration = 0; + /* i_InterruptFlag=0; */ /* i_Initialised=0; */ /* i_Count=0; */ @@ -2788,27 +2420,13 @@ int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_su } /* - +----------------------------------------------------------------------------+ - | Function name : int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, | - | struct comedi_subdevice *s) | - | | - +----------------------------------------------------------------------------+ - | Task : Does asynchronous acquisition | - | Determines the mode 1 or 2. | - | | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev | - | struct comedi_subdevice *s | - | | - | | - +----------------------------------------------------------------------------+ - | Return Value : | - | | - +----------------------------------------------------------------------------+ -*/ - -int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s) + * Does asynchronous acquisition + * Determines the mode 1 or 2. + */ +static int apci3200_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { + struct addi_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int ui_Configuration = 0; /* INT i_CurrentSource = 0; */ @@ -2821,6 +2439,7 @@ int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde unsigned int ui_DelayTime = 0; unsigned int ui_DelayTimeBase = 0; unsigned int ui_DelayMode = 0; + /* i_FirstChannel=cmd->chanlist[0]; */ /* i_LastChannel=cmd->chanlist[1]; */ s_BoardInfos[dev->minor].i_FirstChannel = cmd->chanlist[0]; @@ -2979,80 +2598,153 @@ int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, struct comedi_subde } /* - +----------------------------------------------------------------------------+ - | Function Name : int i_APCI3200_Reset(struct comedi_device *dev) | - | | - +----------------------------------------------------------------------------+ - | Task :Resets the registers of the card | - +----------------------------------------------------------------------------+ - | Input Parameters : | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : | - | | - +----------------------------------------------------------------------------+ -*/ - -int i_APCI3200_Reset(struct comedi_device *dev) + * This function copies the acquired data(from FIFO) to Comedi buffer. + */ +static int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) { - int i_Temp; - unsigned int dw_Dummy; - /* i_InterruptFlag=0; */ - /* i_Initialised==0; */ - /* i_Count=0; */ - /* i_Sum=0; */ + struct addi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int ui_StatusRegister = 0; - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - s_BoardInfos[dev->minor].i_Initialised = 0; - s_BoardInfos[dev->minor].i_Count = 0; - s_BoardInfos[dev->minor].i_Sum = 0; - s_BoardInfos[dev->minor].b_StructInitialized = 0; + /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* comedi_async *async = s->async; */ + /* UINT *data; */ + /* data=async->data+async->buf_int_ptr;//new samples added from here onwards */ + int n = 0, i = 0; + /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - outl(0x83838383, devpriv->i_IobaseAmcc + 0x60); + /************************************/ + /*Read the interrupt status register */ + /************************************/ + /* ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); */ + ui_StatusRegister = + inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 16); - /* Enable the interrupt for the controller */ - dw_Dummy = inl(devpriv->i_IobaseAmcc + 0x38); - outl(dw_Dummy | 0x2000, devpriv->i_IobaseAmcc + 0x38); - outl(0, devpriv->i_IobaseAddon); /* Resets the output */ - /***************/ - /*Empty the buffer */ - /**************/ - for (i_Temp = 0; i_Temp <= 95; i_Temp++) { - /* ui_InterruptChannelValue[i_Temp]=0; */ - s_BoardInfos[dev->minor].ui_InterruptChannelValue[i_Temp] = 0; - } /* for(i_Temp=0;i_Temp<=95;i_Temp++) */ - /*****************************/ - /*Reset the START and IRQ bit */ - /*****************************/ - for (i_Temp = 0; i_Temp <= 192;) { - while (((inl(devpriv->iobase + i_Temp + 12) >> 19) & 1) != 1) ; - outl(0, devpriv->iobase + i_Temp + 8); - i_Temp = i_Temp + 64; - } /* for(i_Temp=0;i_Temp<=192;i_Temp+64) */ + /*************************/ + /*Test if interrupt occur */ + /*************************/ + + if ((ui_StatusRegister & 0x2) == 0x2) { + /*************************/ + /*Read the channel number */ + /*************************/ + /* ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); */ + /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* This value is not used */ + /* ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); */ + /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + + /*************************************/ + /*Read the digital Analog Input value */ + /*************************************/ + + /* data[i_Count] = inl(devpriv->iobase+i_Offset + 28); */ + /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* data[s_BoardInfos [dev->minor].i_Count] = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 28); */ + s_BoardInfos[dev->minor].ui_ScanValueArray[s_BoardInfos[dev-> + minor].i_Count] = + inl(devpriv->iobase + + s_BoardInfos[dev->minor].i_Offset + 28); + /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + + /* if((i_Count == (i_LastChannel-i_FirstChannel+3))) */ + if ((s_BoardInfos[dev->minor].i_Count == + (s_BoardInfos[dev->minor].i_LastChannel - + s_BoardInfos[dev->minor]. + i_FirstChannel + 3))) { + + /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + s_BoardInfos[dev->minor].i_Count++; + + for (i = s_BoardInfos[dev->minor].i_FirstChannel; + i <= s_BoardInfos[dev->minor].i_LastChannel; + i++) { + i_APCI3200_GetChannelCalibrationValue(dev, i, + &s_BoardInfos[dev->minor]. + ui_ScanValueArray[s_BoardInfos[dev-> + minor].i_Count + ((i - + s_BoardInfos + [dev->minor]. + i_FirstChannel) + * 3)], + &s_BoardInfos[dev->minor]. + ui_ScanValueArray[s_BoardInfos[dev-> + minor].i_Count + ((i - + s_BoardInfos + [dev->minor]. + i_FirstChannel) + * 3) + 1], + &s_BoardInfos[dev->minor]. + ui_ScanValueArray[s_BoardInfos[dev-> + minor].i_Count + ((i - + s_BoardInfos + [dev->minor]. + i_FirstChannel) + * 3) + 2]); + } + + /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ + + /* i_Count=-1; */ + + s_BoardInfos[dev->minor].i_Count = -1; + + /* async->buf_int_count+=(i_LastChannel-i_FirstChannel+4)*sizeof(unsigned int); */ + /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* async->buf_int_count+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(unsigned int); */ + /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* async->buf_int_ptr+=(i_LastChannel-i_FirstChannel+4)*sizeof(unsigned int); */ + /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* async->buf_int_ptr+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(unsigned int); */ + /* comedi_eos(dev,s); */ + + /* Set the event type (Comedi Buffer End Of Scan) */ + s->async->events |= COMEDI_CB_EOS; + + /* Test if enougth memory is available and allocate it for 7 values */ + n = comedi_buf_write_alloc(s, + (7 + 12) * sizeof(unsigned int)); + + /* If not enough memory available, event is set to Comedi Buffer Error */ + if (n > ((7 + 12) * sizeof(unsigned int))) { + printk("\ncomedi_buf_write_alloc n = %i", n); + s->async->events |= COMEDI_CB_ERROR; + } + /* Write all 7 scan values in the comedi buffer */ + comedi_buf_memcpy_to(s, 0, + (unsigned int *) s_BoardInfos[dev->minor]. + ui_ScanValueArray, (7 + 12) * sizeof(unsigned int)); + + /* Update comedi buffer pinters indexes */ + comedi_buf_write_free(s, + (7 + 12) * sizeof(unsigned int)); + + /* Send events */ + comedi_event(dev, s); + /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + + /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + /* */ + /* if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over */ + /* { */ + /* /* buffer rollover */ */ + /* s->async->buf_int_ptr=0; */ + /* comedi_eobuf(dev,s); */ + /* } */ + /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ + } + /* i_Count++; */ + s_BoardInfos[dev->minor].i_Count++; + } + /* i_InterruptFlag=0; */ + s_BoardInfos[dev->minor].i_InterruptFlag = 0; return 0; } -/* - +----------------------------------------------------------------------------+ - | Function Name : static void v_APCI3200_Interrupt | - | (int irq , void *d) | - +----------------------------------------------------------------------------+ - | Task : Interrupt processing Routine | - +----------------------------------------------------------------------------+ - | Input Parameters : int irq : irq number | - | void *d : void pointer | - +----------------------------------------------------------------------------+ - | Output Parameters : -- | - +----------------------------------------------------------------------------+ - | Return Value : TRUE : No error occur | - | : FALSE : Error occur. Return the error | - | | - +----------------------------------------------------------------------------+ -*/ -void v_APCI3200_Interrupt(int irq, void *d) +static void apci3200_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct addi_private *devpriv = dev->private; unsigned int ui_StatusRegister = 0; unsigned int ui_ChannelNumber = 0; int i_CalibrationFlag = 0; @@ -3061,7 +2753,6 @@ void v_APCI3200_Interrupt(int irq, void *d) unsigned int ui_DigitalTemperature = 0; unsigned int ui_DigitalInput = 0; int i_ConvertCJCCalibration; - /* BEGIN JK TEST */ int i_ReturnValue = 0; /* END JK TEST */ @@ -3472,164 +3163,3 @@ void v_APCI3200_Interrupt(int irq, void *d) } /* switch(i_ScanType) */ return; } - -/* - +----------------------------------------------------------------------------+ - | Function name :int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) | - | | - | | - +----------------------------------------------------------------------------+ - | Task : . | - | This function copies the acquired data(from FIFO) | - | to Comedi buffer. | - | | - +----------------------------------------------------------------------------+ - | Input Parameters : struct comedi_device *dev | - | | - | | - +----------------------------------------------------------------------------+ - | Return Value : 0 | - | | - +----------------------------------------------------------------------------+ -*/ -int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) -{ - unsigned int ui_StatusRegister = 0; - struct comedi_subdevice *s = dev->subdevices + 0; - - /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* comedi_async *async = s->async; */ - /* UINT *data; */ - /* data=async->data+async->buf_int_ptr;//new samples added from here onwards */ - int n = 0, i = 0; - /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /************************************/ - /*Read the interrupt status register */ - /************************************/ - /* ui_StatusRegister = inl(devpriv->iobase+i_Offset + 16); */ - ui_StatusRegister = - inl(devpriv->iobase + s_BoardInfos[dev->minor].i_Offset + 16); - - /*************************/ - /*Test if interrupt occur */ - /*************************/ - - if ((ui_StatusRegister & 0x2) == 0x2) { - /*************************/ - /*Read the channel number */ - /*************************/ - /* ui_ChannelNumber = inl(devpriv->iobase+i_Offset + 24); */ - /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* This value is not used */ - /* ui_ChannelNumber = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 24); */ - s->async->events = 0; - /* END JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /*************************************/ - /*Read the digital Analog Input value */ - /*************************************/ - - /* data[i_Count] = inl(devpriv->iobase+i_Offset + 28); */ - /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* data[s_BoardInfos [dev->minor].i_Count] = inl(devpriv->iobase+s_BoardInfos [dev->minor].i_Offset + 28); */ - s_BoardInfos[dev->minor].ui_ScanValueArray[s_BoardInfos[dev-> - minor].i_Count] = - inl(devpriv->iobase + - s_BoardInfos[dev->minor].i_Offset + 28); - /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /* if((i_Count == (i_LastChannel-i_FirstChannel+3))) */ - if ((s_BoardInfos[dev->minor].i_Count == - (s_BoardInfos[dev->minor].i_LastChannel - - s_BoardInfos[dev->minor]. - i_FirstChannel + 3))) { - - /* Begin JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - s_BoardInfos[dev->minor].i_Count++; - - for (i = s_BoardInfos[dev->minor].i_FirstChannel; - i <= s_BoardInfos[dev->minor].i_LastChannel; - i++) { - i_APCI3200_GetChannelCalibrationValue(dev, i, - &s_BoardInfos[dev->minor]. - ui_ScanValueArray[s_BoardInfos[dev-> - minor].i_Count + ((i - - s_BoardInfos - [dev->minor]. - i_FirstChannel) - * 3)], - &s_BoardInfos[dev->minor]. - ui_ScanValueArray[s_BoardInfos[dev-> - minor].i_Count + ((i - - s_BoardInfos - [dev->minor]. - i_FirstChannel) - * 3) + 1], - &s_BoardInfos[dev->minor]. - ui_ScanValueArray[s_BoardInfos[dev-> - minor].i_Count + ((i - - s_BoardInfos - [dev->minor]. - i_FirstChannel) - * 3) + 2]); - } - - /* End JK 22.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - - /* i_Count=-1; */ - - s_BoardInfos[dev->minor].i_Count = -1; - - /* async->buf_int_count+=(i_LastChannel-i_FirstChannel+4)*sizeof(unsigned int); */ - /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* async->buf_int_count+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(unsigned int); */ - /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* async->buf_int_ptr+=(i_LastChannel-i_FirstChannel+4)*sizeof(unsigned int); */ - /* Begin JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* async->buf_int_ptr+=(s_BoardInfos [dev->minor].i_LastChannel-s_BoardInfos [dev->minor].i_FirstChannel+4)*sizeof(unsigned int); */ - /* comedi_eos(dev,s); */ - - /* Set the event type (Comedi Buffer End Of Scan) */ - s->async->events |= COMEDI_CB_EOS; - - /* Test if enougth memory is available and allocate it for 7 values */ - /* n = comedi_buf_write_alloc(s->async, 7*sizeof(unsigned int)); */ - n = comedi_buf_write_alloc(s->async, - (7 + 12) * sizeof(unsigned int)); - - /* If not enougth memory available, event is set to Comedi Buffer Errror */ - if (n > ((7 + 12) * sizeof(unsigned int))) { - printk("\ncomedi_buf_write_alloc n = %i", n); - s->async->events |= COMEDI_CB_ERROR; - } - /* Write all 7 scan values in the comedi buffer */ - comedi_buf_memcpy_to(s->async, 0, - (unsigned int *) s_BoardInfos[dev->minor]. - ui_ScanValueArray, (7 + 12) * sizeof(unsigned int)); - - /* Update comedi buffer pinters indexes */ - comedi_buf_write_free(s->async, - (7 + 12) * sizeof(unsigned int)); - - /* Send events */ - comedi_event(dev, s); - /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - /* */ - /* if (s->async->buf_int_ptr>=s->async->data_len) // for buffer rool over */ - /* { */ - /* /* buffer rollover */ */ - /* s->async->buf_int_ptr=0; */ - /* comedi_eobuf(dev,s); */ - /* } */ - /* End JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - } - /* i_Count++; */ - s_BoardInfos[dev->minor].i_Count++; - } - /* i_InterruptFlag=0; */ - s_BoardInfos[dev->minor].i_InterruptFlag = 0; - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h deleted file mode 100644 index 812a9c46e11..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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. - */ - -/* Card Specific information */ -#define APCI3200_BOARD_VENDOR_ID 0x15B8 -/* #define APCI3200_ADDRESS_RANGE 264 */ - -int MODULE_NO; -struct { - int i_Gain; - int i_Polarity; - int i_OffsetRange; - int i_Coupling; - int i_SingleDiff; - int i_AutoCalibration; - unsigned int ui_ReloadValue; - unsigned int ui_TimeUnitReloadVal; - int i_Interrupt; - int i_ModuleSelection; -} Config_Parameters_Module1, Config_Parameters_Module2, - Config_Parameters_Module3, Config_Parameters_Module4; - -/* ANALOG INPUT RANGE */ -static const struct comedi_lrange range_apci3200_ai = { 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -static const struct comedi_lrange range_apci3300_ai = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1) - } -}; - -/* Analog Input related Defines */ -#define APCI3200_AI_OFFSET_GAIN 0 -#define APCI3200_AI_SC_TEST 4 -#define APCI3200_AI_IRQ 8 -#define APCI3200_AI_AUTOCAL 12 -#define APCI3200_RELOAD_CONV_TIME_VAL 32 -#define APCI3200_CONV_TIME_TIME_BASE 36 -#define APCI3200_RELOAD_DELAY_TIME_VAL 40 -#define APCI3200_DELAY_TIME_TIME_BASE 44 -#define APCI3200_AI_MODULE1 0 -#define APCI3200_AI_MODULE2 64 -#define APCI3200_AI_MODULE3 128 -#define APCI3200_AI_MODULE4 192 -#define TRUE 1 -#define FALSE 0 -#define APCI3200_AI_EOSIRQ 16 -#define APCI3200_AI_EOS 20 -#define APCI3200_AI_CHAN_ID 24 -#define APCI3200_AI_CHAN_VAL 28 -#define ANALOG_INPUT 0 -#define TEMPERATURE 1 -#define RESISTANCE 2 - -#define ENABLE_EXT_TRIG 1 -#define ENABLE_EXT_GATE 2 -#define ENABLE_EXT_TRIG_GATE 3 - -#define APCI3200_MAXVOLT 2.5 -#define ADDIDATA_GREATER_THAN_TEST 0 -#define ADDIDATA_LESS_THAN_TEST 1 - -#define ADDIDATA_UNIPOLAR 1 -#define ADDIDATA_BIPOLAR 2 - -/* BEGIN JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ -#define MAX_MODULE 4 -/* END JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - -struct str_ADDIDATA_RTDStruct { - unsigned int ul_NumberOfValue; - unsigned int *pul_ResistanceValue; - unsigned int *pul_TemperatureValue; -}; - -/* BEGIN JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ -struct str_Module { - - /* Begin JK 05/08/2003 change for Linux */ - unsigned long ul_CurrentSourceCJC; - unsigned long ul_CurrentSource[5]; - /* End JK 05/08/2003 change for Linux */ - - /* Begin CG 15/02/02 Rev 1.0 -> Rev 1.1 : Add Header Type 1 */ - unsigned long ul_GainFactor[8]; /* Gain Factor */ - unsigned int w_GainValue[10]; - /* End CG 15/02/02 Rev 1.0 -> Rev 1.1 : Add Header Type 1 */ -}; - -/* END JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - -/* BEGIN JK 06.07.04: Management of sevrals boards */ -struct str_BoardInfos { - - int i_CJCAvailable; - int i_CJCPolarity; - int i_CJCGain; - int i_InterruptFlag; - int i_ADDIDATAPolarity; - int i_ADDIDATAGain; - int i_AutoCalibration; - int i_ADDIDATAConversionTime; - int i_ADDIDATAConversionTimeUnit; - int i_ADDIDATAType; - int i_ChannelNo; - int i_ChannelCount; - int i_ScanType; - int i_FirstChannel; - int i_LastChannel; - int i_Sum; - int i_Offset; - unsigned int ui_Channel_num; - int i_Count; - int i_Initialised; - /* UINT ui_InterruptChannelValue[96]; //Buffer */ - unsigned int ui_InterruptChannelValue[144]; /* Buffer */ - unsigned char b_StructInitialized; - /* Begin JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - unsigned int ui_ScanValueArray[7 + 12]; /* 7 is the maximal number of channels */ - /* End JK 19.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ - - /* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ - int i_ConnectionType; - int i_NbrOfModule; - struct str_Module s_Module[MAX_MODULE]; - /* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ -}; - -/* END JK 06.07.04: Management of sevrals boards */ - -/* Hardware Layer functions for Apci3200 */ - -/* AI */ - -int i_APCI3200_ConfigAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3200_ReadAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3200_InsnWriteReleaseAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3200_InsnBits_AnalogInput_Test(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3200_StopCyclicAcquisition(struct comedi_device *dev, struct comedi_subdevice *s); -int i_APCI3200_InterruptHandleEos(struct comedi_device *dev); -int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -int i_APCI3200_CommandAnalogInput(struct comedi_device *dev, struct comedi_subdevice *s); -int i_APCI3200_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -/* Interrupt */ -void v_APCI3200_Interrupt(int irq, void *d); -int i_APCI3200_InterruptHandleEos(struct comedi_device *dev); -/* Reset functions */ -int i_APCI3200_Reset(struct comedi_device *dev); - -int i_APCI3200_ReadCJCCalOffset(struct comedi_device *dev, unsigned int *data); -int i_APCI3200_ReadCJCValue(struct comedi_device *dev, unsigned int *data); -int i_APCI3200_ReadCalibrationGainValue(struct comedi_device *dev, unsigned int *data); -int i_APCI3200_ReadCalibrationOffsetValue(struct comedi_device *dev, unsigned int *data); -int i_APCI3200_Read1AnalogInputChannel(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -int i_APCI3200_ReadCJCCalGain(struct comedi_device *dev, unsigned int *data); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c index acaceb01629..e82c3fcd048 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c @@ -1,635 +1,170 @@ -/** -@verbatim +/* Watchdog Related Defines */ -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. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/*. - - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : APCI-3501 | Compiler : GCC | - | Module name : hwdrv_apci3501.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: Eric Stolz | Date : 02/12/2002 | - +-------------------------------+---------------------------------------+ - | Description : Hardware Layer Access For APCI-3501 | - +-----------------------------------------------------------------------+ - | UPDATES | - +----------+-----------+------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Included files | -+----------------------------------------------------------------------------+ -*/ -#include "hwdrv_apci3501.h" - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ReadDigitalInput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel or port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3501_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp; - unsigned int ui_NoOfChannel; - ui_NoOfChannel = CR_CHAN(insn->chanspec); - ui_Temp = data[0]; - *data = inl(devpriv->iobase + APCI3501_DIGITAL_IP); - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if (ui_Temp==0) */ - else { - if (ui_Temp == 1) { - - *data = *data & 0x3; - } /* if (ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* elseif (ui_Temp==1) */ - } /* elseif (ui_Temp==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ConfigDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Digital Output Subdevice. | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[1] : 1 Enable VCC Interrupt | -| 0 Disable VCC Interrupt | -| data[2] : 1 Enable CC Interrupt | -| 0 Disable CC Interrupt | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI3501_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - if ((data[0] != 0) && (data[0] != 1)) { - comedi_error(dev, - "Not a valid Data !!! ,Data should be 1 or 0\n"); - return -EINVAL; - } /* if ( (data[0]!=0) && (data[0]!=1) ) */ - if (data[0]) { - devpriv->b_OutputMemoryStatus = ADDIDATA_ENABLE; - } /* if (data[0]) */ - else { - devpriv->b_OutputMemoryStatus = ADDIDATA_DISABLE; - } /* else if (data[0]) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_WriteDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : writes To the digital Output Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI3501_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp, ui_Temp1; - unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */ - if (devpriv->b_OutputMemoryStatus) { - ui_Temp = inl(devpriv->iobase + APCI3501_DIGITAL_OP); - } /* if(devpriv->b_OutputMemoryStatus ) */ - else { - ui_Temp = 0; - } /* if(devpriv->b_OutputMemoryStatus ) */ - if (data[3] == 0) { - if (data[1] == 0) { - data[0] = (data[0] << ui_NoOfChannel) | ui_Temp; - outl(data[0], devpriv->iobase + APCI3501_DIGITAL_OP); - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - data[0] = (data[0] << (2 * data[2])) | ui_Temp; - outl(data[0], - devpriv->iobase + APCI3501_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==0) */ - else { - if (data[3] == 1) { - if (data[1] == 0) { - data[0] = ~data[0] & 0x1; - ui_Temp1 = 1; - ui_Temp1 = ui_Temp1 << ui_NoOfChannel; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - (data[0] << ui_NoOfChannel) ^ - 0xffffffff; - data[0] = data[0] & ui_Temp; - outl(data[0], - devpriv->iobase + APCI3501_DIGITAL_OP); - } /* if(data[1]==0) */ - else { - if (data[1] == 1) { - data[0] = ~data[0] & 0x3; - ui_Temp1 = 3; - ui_Temp1 = ui_Temp1 << 2 * data[2]; - ui_Temp = ui_Temp | ui_Temp1; - data[0] = - ((data[0] << (2 * - data[2])) ^ - 0xffffffff) & ui_Temp; - outl(data[0], - devpriv->iobase + - APCI3501_DIGITAL_OP); - } /* if(data[1]==1) */ - else { - printk("\nSpecified channel not supported\n"); - } /* else if(data[1]==1) */ - } /* elseif(data[1]==0) */ - } /* if(data[3]==1); */ - else { - printk("\nSpecified functionality does not exist\n"); - return -EINVAL; - } /* if else data[3]==1) */ - } /* if else data[3]==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ReadDigitalOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read value of the selected channel or port | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int ui_NoOfChannels : No Of Channels To read | -| unsigned int *data : Data Pointer to read status | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI3501_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ui_Temp; - unsigned int ui_NoOfChannel; - - ui_NoOfChannel = CR_CHAN(insn->chanspec); - ui_Temp = data[0]; - *data = inl(devpriv->iobase + APCI3501_DIGITAL_OP); - if (ui_Temp == 0) { - *data = (*data >> ui_NoOfChannel) & 0x1; - } /* if (ui_Temp==0) */ - else { - if (ui_Temp == 1) { - *data = *data & 0x3; - - } /* if (ui_Temp==1) */ - else { - printk("\nSpecified channel not supported \n"); - } /* else if (ui_Temp==1) */ - } /* else if (ui_Temp==0) */ - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ConfigAnalogOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Analog Output Subdevice | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : Voltage Mode | -| 0:Mode 0 | -| 1:Mode 1 | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - outl(data[0], - devpriv->iobase + APCI3501_ANALOG_OUTPUT + - APCI3501_AO_VOLT_MODE); - - if (data[0]) { - devpriv->b_InterruptMode = MODE1; - } else { - devpriv->b_InterruptMode = MODE0; - } - return insn->n; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_WriteAnalogOutput | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Writes To the Selected Anlog Output Channel | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| struct comedi_subdevice *s : Subdevice Pointer | -| struct comedi_insn *insn : Insn Structure Pointer | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int ul_Command1 = 0, ul_Channel_no, ul_Polarity, ul_DAC_Ready = 0; - - ul_Channel_no = CR_CHAN(insn->chanspec); - - if (devpriv->b_InterruptMode == MODE1) { - ul_Polarity = 0x80000000; - if ((*data < 0) || (*data > 16384)) { - printk("\nIn WriteAnalogOutput :: Not Valid Data\n"); - } - - } /* end if(devpriv->b_InterruptMode==MODE1) */ - else { - ul_Polarity = 0; - if ((*data < 0) || (*data > 8192)) { - printk("\nIn WriteAnalogOutput :: Not Valid Data\n"); - } - - } /* end else */ - - if ((ul_Channel_no < 0) || (ul_Channel_no > 7)) { - printk("\nIn WriteAnalogOutput :: Not Valid Channel\n"); - } /* end if((ul_Channel_no<0)||(ul_Channel_no>7)) */ - - ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); - - while (ul_DAC_Ready == 0) { - ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); - ul_DAC_Ready = (ul_DAC_Ready >> 8) & 1; - } - - if (ul_DAC_Ready) { -/* Output the Value on the output channels. */ - ul_Command1 = - (unsigned int) ((unsigned int) (ul_Channel_no & 0xFF) | - (unsigned int) ((*data << 0x8) & 0x7FFFFF00L) | - (unsigned int) (ul_Polarity)); - outl(ul_Command1, - devpriv->iobase + APCI3501_ANALOG_OUTPUT + - APCI3501_AO_PROG); - } - - return insn->n; -} +#define ADDIDATA_TIMER 0 +#define ADDIDATA_WATCHDOG 2 /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ConfigTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Configures The Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Configure As Timer | -| 1 Configure As Counter | -| 2 Configure As Watchdog | -| data[1] : 1 Enable Interrupt | -| 0 Disable Interrupt | -| data[2] : Time Unit | -| data[3] : Reload Value | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) + * (*insn_config) for the timer subdevice + * + * Configures The Timer, Counter or Watchdog + * Data Pointer contains configuration parameters as below + * data[0] : 0 Configure As Timer + * 1 Configure As Counter + * 2 Configure As Watchdog + * data[1] : 1 Enable Interrupt + * 0 Disable Interrupt + * data[2] : Time Unit + * data[3] : Reload Value + */ +static int apci3501_config_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; + devpriv->tsk_Current = current; if (data[0] == ADDIDATA_WATCHDOG) { devpriv->b_TimerSelectMode = ADDIDATA_WATCHDOG; /* Disable the watchdog */ - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Wa */ + outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); if (data[1] == 1) { /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ - outl(0x02, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(0x02, dev->iobase + APCI3501_TIMER_CTRL_REG); } else { - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Timer interrupt */ + /* disable Timer interrupt */ + outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); } - /* Loading the Timebase value */ - outl(data[2], - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TIMEBASE); + outl(data[2], dev->iobase + APCI3501_TIMER_TIMEBASE_REG); + outl(data[3], dev->iobase + APCI3501_TIMER_RELOAD_REG); - /* Loading the Reload value */ - outl(data[3], - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_RELOAD_VALUE); - /* Set the mode */ - ul_Command1 = inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG) | 0xFFF819E0UL; /* e2->e0 */ - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); - } /* end if(data[0]==ADDIDATA_WATCHDOG) */ + /* Set the mode (e2->e0) */ + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG) | 0xFFF819E0UL; + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + } else if (data[0] == ADDIDATA_TIMER) { /* First Stop The Timer */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* Stop The Timer */ + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); devpriv->b_TimerSelectMode = ADDIDATA_TIMER; if (data[1] == 1) { /* Enable TIMER int & DISABLE ALL THE OTHER int SOURCES */ - outl(0x02, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(0x02, dev->iobase + APCI3501_TIMER_CTRL_REG); } else { - outl(0x0, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* disable Timer interrupt */ + /* disable Timer interrupt */ + outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); } - /* Loading Timebase */ - outl(data[2], - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TIMEBASE); + outl(data[2], dev->iobase + APCI3501_TIMER_TIMEBASE_REG); + outl(data[3], dev->iobase + APCI3501_TIMER_RELOAD_REG); - /* Loading the Reload value */ - outl(data[3], - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_RELOAD_VALUE); - - /* printk ("\nTimer Address :: %x\n", (devpriv->iobase+APCI3501_WATCHDOG)); */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + /* mode 2 */ + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFF719E2UL) | 2UL << 13UL | 0x10UL; - outl(ul_Command1, devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); /* mode 2 */ - - } /* end if(data[0]==ADDIDATA_TIMER) */ + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + } return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_StartStopWriteTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Start / Stop The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Timer | -| 1 Counter | -| 2 Watchdog | | data[1] : 1 Start | -| 0 Stop | 2 Trigger | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) + * (*insn_write) for the timer subdevice + * + * Start / Stop The Selected Timer , Counter or Watchdog + * Data Pointer contains configuration parameters as below + * data[0] : 0 Timer + * 1 Counter + * 2 Watchdog + * data[1] : 1 Start + * 0 Stop + * 2 Trigger + */ +static int apci3501_write_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct apci3501_private *devpriv = dev->private; unsigned int ul_Command1 = 0; int i_Temp; + if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { if (data[1] == 1) { - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Watchdog */ - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); - } - - else if (data[1] == 0) /* Stop The Watchdog */ - { - /* Stop The Watchdog */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + } else if (data[1] == 0) { /* Stop The Watchdog */ + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(0x0, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(0x0, dev->iobase + APCI3501_TIMER_CTRL_REG); } else if (data[1] == 2) { - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x200UL; - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); - } /* if(data[1]==2) */ - } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + } + } if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { if (data[1] == 1) { - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x1UL; /* Enable the Timer */ - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); } else if (data[1] == 0) { /* Stop The Timer */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = ul_Command1 & 0xFFFFF9FEUL; - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); } else if (data[1] == 2) { /* Trigger the Timer */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); ul_Command1 = (ul_Command1 & 0xFFFFF9FFUL) | 0x200UL; - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_PROG); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); } + } - } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ - i_Temp = inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TRIG_STATUS) & 0x1; + i_Temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; return insn->n; } /* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_ReadTimerCounterWatchdog | -| (struct comedi_device *dev,struct comedi_subdevice *s, | -| struct comedi_insn *insn,unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read The Selected Timer , Counter or Watchdog | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev : Driver handle | -| unsigned int *data : Data Pointer contains | -| configuration parameters as below | -| | -| data[0] : 0 Timer | -| 1 Counter | -| 2 Watchdog | | data[1] : Timer Counter Watchdog Number | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) + * (*insn_read) for the timer subdevice + * + * Read The Selected Timer, Counter or Watchdog + * Data Pointer contains configuration parameters as below + * data[0] : 0 Timer + * 1 Counter + * 2 Watchdog + * data[1] : Timer Counter Watchdog Number + */ +static int apci3501_read_insn_timer(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct apci3501_private *devpriv = dev->private; if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) { - data[0] = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TRIG_STATUS) & 0x1; - data[1] = inl(devpriv->iobase + APCI3501_WATCHDOG); - } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_WATCHDOG) */ + data[0] = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; + data[1] = inl(dev->iobase + APCI3501_TIMER_SYNC_REG); + } else if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) { - data[0] = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TRIG_STATUS) & 0x1; - data[1] = inl(devpriv->iobase + APCI3501_WATCHDOG); - } /* end if (devpriv->b_TimerSelectMode==ADDIDATA_TIMER) */ + data[0] = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; + data[1] = inl(dev->iobase + APCI3501_TIMER_SYNC_REG); + } else if ((devpriv->b_TimerSelectMode != ADDIDATA_TIMER) && (devpriv->b_TimerSelectMode != ADDIDATA_WATCHDOG)) { @@ -637,107 +172,3 @@ int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, } return insn->n; } - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3501_Reset(struct comedi_device *dev) | -| | -+----------------------------------------------------------------------------+ -| Task :Resets the registers of the card | -+----------------------------------------------------------------------------+ -| Input Parameters : | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : | -| | -+----------------------------------------------------------------------------+ -*/ - -int i_APCI3501_Reset(struct comedi_device *dev) -{ - int i_Count = 0, i_temp = 0; - unsigned int ul_Command1 = 0, ul_Polarity, ul_DAC_Ready = 0; - outl(0x0, devpriv->iobase + APCI3501_DIGITAL_OP); - outl(1, devpriv->iobase + APCI3501_ANALOG_OUTPUT + - APCI3501_AO_VOLT_MODE); - - ul_Polarity = 0x80000000; - - for (i_Count = 0; i_Count <= 7; i_Count++) { - ul_DAC_Ready = inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); - - while (ul_DAC_Ready == 0) { - ul_DAC_Ready = - inl(devpriv->iobase + APCI3501_ANALOG_OUTPUT); - ul_DAC_Ready = (ul_DAC_Ready >> 8) & 1; - } - - if (ul_DAC_Ready) { - /* Output the Value on the output channels. */ - ul_Command1 = - (unsigned int) ((unsigned int) (i_Count & 0xFF) | - (unsigned int) ((i_temp << 0x8) & 0x7FFFFF00L) | - (unsigned int) (ul_Polarity)); - outl(ul_Command1, - devpriv->iobase + APCI3501_ANALOG_OUTPUT + - APCI3501_AO_PROG); - } - } - - return 0; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : static void v_APCI3501_Interrupt | -| (int irq , void *d) | -+----------------------------------------------------------------------------+ -| Task : Interrupt processing Routine | -+----------------------------------------------------------------------------+ -| Input Parameters : int irq : irq number | -| void *d : void pointer | -+----------------------------------------------------------------------------+ -| Output Parameters : -- | -+----------------------------------------------------------------------------+ -| Return Value : TRUE : No error occur | -| : FALSE : Error occur. Return the error | -| | -+----------------------------------------------------------------------------+ -*/ -void v_APCI3501_Interrupt(int irq, void *d) -{ - int i_temp; - struct comedi_device *dev = d; - unsigned int ui_Timer_AOWatchdog; - unsigned long ul_Command1; - /* Disable Interrupt */ - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - - ul_Command1 = (ul_Command1 & 0xFFFFF9FDul); - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - - ui_Timer_AOWatchdog = - inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_IRQ) & 0x1; - - if ((!ui_Timer_AOWatchdog)) { - comedi_error(dev, "IRQ from unknown source"); - return; - } - -/* -* Enable Interrupt Send a signal to from kernel to user space -*/ - send_sig(SIGIO, devpriv->tsk_Current, 0); - ul_Command1 = - inl(devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1); - outl(ul_Command1, - devpriv->iobase + APCI3501_WATCHDOG + APCI3501_TCW_PROG); - i_temp = inl(devpriv->iobase + APCI3501_WATCHDOG + - APCI3501_TCW_TRIG_STATUS) & 0x1; - return; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h deleted file mode 100644 index 63df635a7b6..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * 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. - */ - -/* Card Specific information */ -#define APCI3501_BOARD_VENDOR_ID 0x15B8 -#define APCI3501_ADDRESS_RANGE 255 - -#define APCI3501_DIGITAL_IP 0x50 -#define APCI3501_DIGITAL_OP 0x40 -#define APCI3501_ANALOG_OUTPUT 0x00 - -/* Analog Output related Defines */ -#define APCI3501_AO_VOLT_MODE 0 -#define APCI3501_AO_PROG 4 -#define APCI3501_AO_TRIG_SCS 8 -#define UNIPOLAR 0 -#define BIPOLAR 1 -#define MODE0 0 -#define MODE1 1 -/* ANALOG OUTPUT RANGE */ -static struct comedi_lrange range_apci3501_ao = { 2, { - BIP_RANGE(10), - UNI_RANGE(10) - } -}; - -/* Watchdog Related Defines */ - -#define APCI3501_WATCHDOG 0x20 -#define APCI3501_TCW_SYNC_ENABLEDISABLE 0 -#define APCI3501_TCW_RELOAD_VALUE 4 -#define APCI3501_TCW_TIMEBASE 8 -#define APCI3501_TCW_PROG 12 -#define APCI3501_TCW_TRIG_STATUS 16 -#define APCI3501_TCW_IRQ 20 -#define APCI3501_TCW_WARN_TIMEVAL 24 -#define APCI3501_TCW_WARN_TIMEBASE 28 -#define ADDIDATA_TIMER 0 -#define ADDIDATA_WATCHDOG 2 - -/* Hardware Layer functions for Apci3501 */ - -/* AO */ -int i_APCI3501_ConfigAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3501_WriteAnalogOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* -* DI for di read INT i_APCI3501_ReadDigitalInput(struct -* comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn -* *insn,unsigned int *data); -*/ - -int i_APCI3501_ReadDigitalInput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* DO */ -int i_APCI3501_ConfigDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3501_WriteDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3501_ReadDigitalOutput(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* TIMER - * timer value is passed as u seconds - */ - -int i_APCI3501_ConfigTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int i_APCI3501_StartStopWriteTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -int i_APCI3501_ReadTimerCounterWatchdog(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -/* Interrupt */ -void v_APCI3501_Interrupt(int irq, void *d); - -/* Reset functions */ -int i_APCI3501_Reset(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c deleted file mode 100644 index fff99df51e9..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.c +++ /dev/null @@ -1,1664 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstrasse 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-----------------------------------------------------------------------+ - | Project : APCI-3XXX | Compiler : GCC | - | Module name : hwdrv_apci3xxx.c| Version : 2.96 | - +-------------------------------+---------------------------------------+ - | Project manager: S. Weber | Date : 15/09/2005 | - +-----------------------------------------------------------------------+ - | Description :APCI3XXX Module. Hardware abstraction Layer for APCI3XXX| - +-----------------------------------------------------------------------+ - | UPDATE'S | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | | | | - | | | | - +----------+-----------+------------------------------------------------+ -*/ - -#include "hwdrv_apci3xxx.h" - -/* -+----------------------------------------------------------------------------+ -| ANALOG INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_TestConversionStarted | -| (struct comedi_device *dev) | -+----------------------------------------------------------------------------+ -| Task Test if any conversion started | -+----------------------------------------------------------------------------+ -| Input Parameters : - | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 : Conversion not started | -| 1 : Conversion started | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_TestConversionStarted(struct comedi_device *dev) -{ - if ((readl(devpriv->dw_AiBase + 8) & 0x80000UL) == 0x80000UL) - return 1; - else - return 0; - -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_AnalogInputConfigOperatingMode | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task Converting mode and convert time selection | -+----------------------------------------------------------------------------+ -| Input Parameters : b_SingleDiff = (unsigned char) data[1]; | -| b_TimeBase = (unsigned char) data[2]; (0: ns, 1:micros 2:ms)| -| dw_ReloadValue = (unsigned int) data[3]; | -| ........ | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0 : No error | -| -1 : Single/Diff selection error | -| -2 : Convert time base unity selection error | -| -3 : Convert time value selection error | -| -10: Any conversion started | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_AnalogInputConfigOperatingMode(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_TimeBase = 0; - unsigned char b_SingleDiff = 0; - unsigned int dw_ReloadValue = 0; - unsigned int dw_TestReloadValue = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n == 4) { - /****************************/ - /* Get the Singel/Diff flag */ - /****************************/ - - b_SingleDiff = (unsigned char) data[1]; - - /****************************/ - /* Get the time base unitiy */ - /****************************/ - - b_TimeBase = (unsigned char) data[2]; - - /*************************************/ - /* Get the convert time reload value */ - /*************************************/ - - dw_ReloadValue = (unsigned int) data[3]; - - /**********************/ - /* Test the time base */ - /**********************/ - - if ((this_board->b_AvailableConvertUnit & (1 << b_TimeBase)) != - 0) { - /*******************************/ - /* Test the convert time value */ - /*******************************/ - - if (dw_ReloadValue <= 65535) { - dw_TestReloadValue = dw_ReloadValue; - - if (b_TimeBase == 1) { - dw_TestReloadValue = - dw_TestReloadValue * 1000UL; - } - if (b_TimeBase == 2) { - dw_TestReloadValue = - dw_TestReloadValue * 1000000UL; - } - - /*******************************/ - /* Test the convert time value */ - /*******************************/ - - if (dw_TestReloadValue >= - devpriv->s_EeParameters. - ui_MinAcquisitiontimeNs) { - if ((b_SingleDiff == APCI3XXX_SINGLE) - || (b_SingleDiff == - APCI3XXX_DIFF)) { - if (((b_SingleDiff == APCI3XXX_SINGLE) - && (devpriv->s_EeParameters.i_NbrAiChannel == 0)) - || ((b_SingleDiff == APCI3XXX_DIFF) - && (this_board->i_NbrAiChannelDiff == 0)) - ) { - /*******************************/ - /* Single/Diff selection error */ - /*******************************/ - - printk("Single/Diff selection error\n"); - i_ReturnValue = -1; - } else { - /**********************************/ - /* Test if conversion not started */ - /**********************************/ - - if (i_APCI3XXX_TestConversionStarted(dev) == 0) { - devpriv-> - ui_EocEosConversionTime - = - (unsigned int) - dw_ReloadValue; - devpriv-> - b_EocEosConversionTimeBase - = - b_TimeBase; - devpriv-> - b_SingelDiff - = - b_SingleDiff; - devpriv-> - b_AiInitialisation - = 1; - - /*******************************/ - /* Set the convert timing unit */ - /*******************************/ - - writel((unsigned int)b_TimeBase, - devpriv->dw_AiBase + 36); - - /**************************/ - /* Set the convert timing */ - /*************************/ - - writel(dw_ReloadValue, devpriv->dw_AiBase + 32); - } else { - /**************************/ - /* Any conversion started */ - /**************************/ - - printk("Any conversion started\n"); - i_ReturnValue = - -10; - } - } - } else { - /*******************************/ - /* Single/Diff selection error */ - /*******************************/ - - printk("Single/Diff selection error\n"); - i_ReturnValue = -1; - } - } else { - /************************/ - /* Time selection error */ - /************************/ - - printk("Convert time value selection error\n"); - i_ReturnValue = -3; - } - } else { - /************************/ - /* Time selection error */ - /************************/ - - printk("Convert time value selection error\n"); - i_ReturnValue = -3; - } - } else { - /*****************************/ - /* Time base selection error */ - /*****************************/ - - printk("Convert time base unity selection error\n"); - i_ReturnValue = -2; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnConfigAnalogInput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task Converting mode and convert time selection | -+----------------------------------------------------------------------------+ -| Input Parameters : b_ConvertMode = (unsigned char) data[0]; | -| b_TimeBase = (unsigned char) data[1]; (0: ns, 1:micros 2:ms)| -| dw_ReloadValue = (unsigned int) data[2]; | -| ........ | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnConfigAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - switch ((unsigned char) data[0]) { - case APCI3XXX_CONFIGURATION: - i_ReturnValue = - i_APCI3XXX_AnalogInputConfigOperatingMode(dev, - s, insn, data); - break; - - default: - i_ReturnValue = -100; - printk("Config command error %d\n", data[0]); - break; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnReadAnalogInput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task Read 1 analog input | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Range = CR_RANGE(insn->chanspec); | -| b_Channel = CR_CHAN(insn->chanspec); | -| dw_NbrOfAcquisition = insn->n; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -3 : Channel selection error | -| -4 : Configuration selelection error | -| -10: Any conversion started | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnReadAnalogInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Configuration = (unsigned char) CR_RANGE(insn->chanspec); - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - unsigned int dw_Temp = 0; - unsigned int dw_Configuration = 0; - unsigned int dw_AcquisitionCpt = 0; - unsigned char b_Interrupt = 0; - - /*************************************/ - /* Test if operating mode configured */ - /*************************************/ - - if (devpriv->b_AiInitialisation) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if (((b_Channel < devpriv->s_EeParameters.i_NbrAiChannel) - && (devpriv->b_SingelDiff == APCI3XXX_SINGLE)) - || ((b_Channel < this_board->i_NbrAiChannelDiff) - && (devpriv->b_SingelDiff == APCI3XXX_DIFF))) { - /**********************************/ - /* Test the channel configuration */ - /**********************************/ - - if (b_Configuration > 7) { - /***************************/ - /* Channel not initialised */ - /***************************/ - - i_ReturnValue = -4; - printk("Channel %d range %d selection error\n", - b_Channel, b_Configuration); - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", b_Channel); - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - /************************/ - /* Test the buffer size */ - /************************/ - - if ((b_Interrupt != 0) || ((b_Interrupt == 0) - && (insn->n >= 1))) { - /**********************************/ - /* Test if conversion not started */ - /**********************************/ - - if (i_APCI3XXX_TestConversionStarted(dev) == 0) { - /******************/ - /* Clear the FIFO */ - /******************/ - - writel(0x10000UL, devpriv->dw_AiBase + 12); - - /*******************************/ - /* Get and save the delay mode */ - /*******************************/ - - dw_Temp = readl(devpriv->dw_AiBase + 4); - dw_Temp = dw_Temp & 0xFFFFFEF0UL; - - /***********************************/ - /* Channel configuration selection */ - /***********************************/ - - writel(dw_Temp, devpriv->dw_AiBase + 4); - - /**************************/ - /* Make the configuration */ - /**************************/ - - dw_Configuration = - (b_Configuration & 3) | - ((unsigned int) (b_Configuration >> 2) - << 6) | ((unsigned int) devpriv-> - b_SingelDiff << 7); - - /***************************/ - /* Write the configuration */ - /***************************/ - - writel(dw_Configuration, - devpriv->dw_AiBase + 0); - - /*********************/ - /* Channel selection */ - /*********************/ - - writel(dw_Temp | 0x100UL, - devpriv->dw_AiBase + 4); - writel((unsigned int) b_Channel, - devpriv->dw_AiBase + 0); - - /***********************/ - /* Restaure delay mode */ - /***********************/ - - writel(dw_Temp, devpriv->dw_AiBase + 4); - - /***********************************/ - /* Set the number of sequence to 1 */ - /***********************************/ - - writel(1, devpriv->dw_AiBase + 48); - - /***************************/ - /* Save the interrupt flag */ - /***************************/ - - devpriv->b_EocEosInterrupt = - b_Interrupt; - - /*******************************/ - /* Save the number of channels */ - /*******************************/ - - devpriv->ui_AiNbrofChannels = 1; - - /******************************/ - /* Test if interrupt not used */ - /******************************/ - - if (b_Interrupt == 0) { - for (dw_AcquisitionCpt = 0; - dw_AcquisitionCpt < - insn->n; - dw_AcquisitionCpt++) { - /************************/ - /* Start the conversion */ - /************************/ - - writel(0x80000UL, devpriv->dw_AiBase + 8); - - /****************/ - /* Wait the EOS */ - /****************/ - - do { - dw_Temp = readl(devpriv->dw_AiBase + 20); - dw_Temp = dw_Temp & 1; - } while (dw_Temp != 1); - - /*************************/ - /* Read the analog value */ - /*************************/ - - data[dw_AcquisitionCpt] = (unsigned int)readl(devpriv->dw_AiBase + 28); - } - } else { - /************************/ - /* Start the conversion */ - /************************/ - - writel(0x180000UL, devpriv->dw_AiBase + 8); - } - } else { - /**************************/ - /* Any conversion started */ - /**************************/ - - printk("Any conversion started\n"); - i_ReturnValue = -10; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - printk("Operating mode not configured\n"); - i_ReturnValue = -1; - } - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function name : void v_APCI3XXX_Interrupt (int irq, | -| void *d) | -+----------------------------------------------------------------------------+ -| Task :Interrupt handler for APCI3XXX | -| When interrupt occurs this gets called. | -| First it finds which interrupt has been generated and | -| handles corresponding interrupt | -+----------------------------------------------------------------------------+ -| Input Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : - | -+----------------------------------------------------------------------------+ -*/ - -static void v_APCI3XXX_Interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - unsigned char b_CopyCpt = 0; - unsigned int dw_Status = 0; - - /***************************/ - /* Test if interrupt occur */ - /***************************/ - - dw_Status = readl(devpriv->dw_AiBase + 16); - if ( (dw_Status & 0x2UL) == 0x2UL) { - /***********************/ - /* Reset the interrupt */ - /***********************/ - - writel(dw_Status, devpriv->dw_AiBase + 16); - - /*****************************/ - /* Test if interrupt enabled */ - /*****************************/ - - if (devpriv->b_EocEosInterrupt == 1) { - /********************************/ - /* Read all analog inputs value */ - /********************************/ - - for (b_CopyCpt = 0; - b_CopyCpt < devpriv->ui_AiNbrofChannels; - b_CopyCpt++) { - devpriv->ui_AiReadData[b_CopyCpt] = - (unsigned int)readl(devpriv->dw_AiBase + 28); - } - - /**************************/ - /* Set the interrupt flag */ - /**************************/ - - devpriv->b_EocEosInterrupt = 2; - - /**********************************************/ - /* Send a signal to from kernel to user space */ - /**********************************************/ - - send_sig(SIGIO, devpriv->tsk_Current, 0); - } - } -} - -/* -+----------------------------------------------------------------------------+ -| ANALOG OUTPUT SUBDEVICE | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnWriteAnalogOutput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task Read 1 analog input | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Range = CR_RANGE(insn->chanspec); | -| b_Channel = CR_CHAN(insn->chanspec); | -| data[0] = analog value; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -3 : Channel selection error | -| -4 : Configuration selelection error | -| .... | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnWriteAnalogOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned char b_Range = (unsigned char) CR_RANGE(insn->chanspec); - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - unsigned int dw_Status = 0; - int i_ReturnValue = insn->n; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if (b_Channel < devpriv->s_EeParameters.i_NbrAoChannel) { - /**********************************/ - /* Test the channel configuration */ - /**********************************/ - - if (b_Range < 2) { - /***************************/ - /* Set the range selection */ - /***************************/ - - writel(b_Range, devpriv->dw_AiBase + 96); - - /**************************************************/ - /* Write the analog value to the selected channel */ - /**************************************************/ - - writel((data[0] << 8) | b_Channel, - devpriv->dw_AiBase + 100); - - /****************************/ - /* Wait the end of transfer */ - /****************************/ - - do { - dw_Status = readl(devpriv->dw_AiBase + 96); - } while ((dw_Status & 0x100) != 0x100); - } else { - /***************************/ - /* Channel not initialised */ - /***************************/ - - i_ReturnValue = -4; - printk("Channel %d range %d selection error\n", - b_Channel, b_Range); - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", b_Channel); - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| TTL FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnConfigInitTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task You must calling this function be | -| for you call any other function witch access of TTL. | -| APCI3XXX_TTL_INIT_DIRECTION_PORT2(user inputs for direction)| -+----------------------------------------------------------------------------+ -| Input Parameters : b_InitType = (unsigned char) data[0]; | -| b_Port2Mode = (unsigned char) data[1]; | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| -1: Port 2 mode selection is wrong | -| .... | -| -100 : Config command error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnConfigInitTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Command = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /*******************/ - /* Get the command */ - /* **************** */ - - b_Command = (unsigned char) data[0]; - - /********************/ - /* Test the command */ - /********************/ - - if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) { - /***************************************/ - /* Test the initialisation buffer size */ - /***************************************/ - - if ((b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) - && (insn->n != 2)) { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("Command selection error\n"); - i_ReturnValue = -100; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - /*********************************************************************************/ - /* Test if no error occur and APCI3XXX_TTL_INIT_DIRECTION_PORT2 command selected */ - /*********************************************************************************/ - - if ((i_ReturnValue >= 0) - && (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2)) { - /**********************/ - /* Test the direction */ - /**********************/ - - if ((data[1] == 0) || (data[1] == 0xFF)) { - /**************************/ - /* Save the configuration */ - /**************************/ - - devpriv->ul_TTLPortConfiguration[0] = - devpriv->ul_TTLPortConfiguration[0] | data[1]; - } else { - /************************/ - /* Port direction error */ - /************************/ - - printk("Port 2 direction selection error\n"); - i_ReturnValue = -1; - } - } - - /**************************/ - /* Test if no error occur */ - /**************************/ - - if (i_ReturnValue >= 0) { - /***********************************/ - /* Test if TTL port initilaisation */ - /***********************************/ - - if (b_Command == APCI3XXX_TTL_INIT_DIRECTION_PORT2) { - /*************************/ - /* Set the configuration */ - /*************************/ - - outl(data[1], devpriv->iobase + 224); - } - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| TTL INPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnBitsTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Write the selected output mask and read the status from| -| all TTL channles | -+----------------------------------------------------------------------------+ -| Input Parameters : dw_ChannelMask = data [0]; | -| dw_BitMask = data [1]; | -+----------------------------------------------------------------------------+ -| Output Parameters : data[1] : All TTL channles states | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -4 : Channel mask error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnBitsTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_ChannelCpt = 0; - unsigned int dw_ChannelMask = 0; - unsigned int dw_BitMask = 0; - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 2) { - /*******************************/ - /* Get the channe and bit mask */ - /*******************************/ - - dw_ChannelMask = data[0]; - dw_BitMask = data[1]; - - /*************************/ - /* Test the channel mask */ - /*************************/ - - if (((dw_ChannelMask & 0XFF00FF00) == 0) && - (((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0xFF) - || (((devpriv->ul_TTLPortConfiguration[0] & - 0xFF) == 0) - && ((dw_ChannelMask & 0XFF0000) == - 0)))) { - /*********************************/ - /* Test if set/reset any channel */ - /*********************************/ - - if (dw_ChannelMask) { - /****************************************/ - /* Test if set/rest any port 0 channels */ - /****************************************/ - - if (dw_ChannelMask & 0xFF) { - /*******************************************/ - /* Read port 0 (first digital output port) */ - /*******************************************/ - - dw_Status = inl(devpriv->iobase + 80); - - for (b_ChannelCpt = 0; b_ChannelCpt < 8; - b_ChannelCpt++) { - if ((dw_ChannelMask >> - b_ChannelCpt) & - 1) { - dw_Status = - (dw_Status & - (0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt)); - } - } - - outl(dw_Status, devpriv->iobase + 80); - } - - /****************************************/ - /* Test if set/rest any port 2 channels */ - /****************************************/ - - if (dw_ChannelMask & 0xFF0000) { - dw_BitMask = dw_BitMask >> 16; - dw_ChannelMask = dw_ChannelMask >> 16; - - /********************************************/ - /* Read port 2 (second digital output port) */ - /********************************************/ - - dw_Status = inl(devpriv->iobase + 112); - - for (b_ChannelCpt = 0; b_ChannelCpt < 8; - b_ChannelCpt++) { - if ((dw_ChannelMask >> - b_ChannelCpt) & - 1) { - dw_Status = - (dw_Status & - (0xFF - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt)); - } - } - - outl(dw_Status, devpriv->iobase + 112); - } - } - - /*******************************************/ - /* Read port 0 (first digital output port) */ - /*******************************************/ - - data[1] = inl(devpriv->iobase + 80); - - /******************************************/ - /* Read port 1 (first digital input port) */ - /******************************************/ - - data[1] = data[1] | (inl(devpriv->iobase + 64) << 8); - - /************************/ - /* Test if port 2 input */ - /************************/ - - if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF) == 0) { - data[1] = - data[1] | (inl(devpriv->iobase + - 96) << 16); - } else { - data[1] = - data[1] | (inl(devpriv->iobase + - 112) << 16); - } - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("Channel mask error\n"); - i_ReturnValue = -4; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnReadTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the status from selected channel | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Channel = CR_CHAN(insn->chanspec) | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : Selected TTL channel state | -+----------------------------------------------------------------------------+ -| Return Value : 0 : No error | -| -3 : Channel selection error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnReadTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - int i_ReturnValue = insn->n; - unsigned int *pls_ReadData = data; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /***********************/ - /* Test if read port 0 */ - /***********************/ - - if (b_Channel < 8) { - /*******************************************/ - /* Read port 0 (first digital output port) */ - /*******************************************/ - - pls_ReadData[0] = inl(devpriv->iobase + 80); - pls_ReadData[0] = (pls_ReadData[0] >> b_Channel) & 1; - } else { - /***********************/ - /* Test if read port 1 */ - /***********************/ - - if ((b_Channel > 7) && (b_Channel < 16)) { - /******************************************/ - /* Read port 1 (first digital input port) */ - /******************************************/ - - pls_ReadData[0] = inl(devpriv->iobase + 64); - pls_ReadData[0] = - (pls_ReadData[0] >> (b_Channel - - 8)) & 1; - } else { - /***********************/ - /* Test if read port 2 */ - /***********************/ - - if ((b_Channel > 15) && (b_Channel < 24)) { - /************************/ - /* Test if port 2 input */ - /************************/ - - if ((devpriv->ul_TTLPortConfiguration[0] - & 0xFF) == 0) { - pls_ReadData[0] = - inl(devpriv->iobase + - 96); - pls_ReadData[0] = - (pls_ReadData[0] >> - (b_Channel - 16)) & 1; - } else { - pls_ReadData[0] = - inl(devpriv->iobase + - 112); - pls_ReadData[0] = - (pls_ReadData[0] >> - (b_Channel - 16)) & 1; - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", - b_Channel); - } - } - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| TTL OUTPUT FUNCTIONS | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_InsnWriteTTLIO | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Set the state from TTL output channel | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Channel = CR_CHAN(insn->chanspec) | -| b_State = data [0] | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : 0 : No error | -| -3 : Channel selection error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnWriteTTLIO(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - unsigned char b_State = 0; - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - b_State = (unsigned char) data[0]; - - /***********************/ - /* Test if read port 0 */ - /***********************/ - - if (b_Channel < 8) { - /*****************************************************************************/ - /* Read port 0 (first digital output port) and set/reset the selected channel */ - /*****************************************************************************/ - - dw_Status = inl(devpriv->iobase + 80); - dw_Status = - (dw_Status & (0xFF - - (1 << b_Channel))) | ((b_State & 1) << - b_Channel); - outl(dw_Status, devpriv->iobase + 80); - } else { - /***********************/ - /* Test if read port 2 */ - /***********************/ - - if ((b_Channel > 15) && (b_Channel < 24)) { - /*************************/ - /* Test if port 2 output */ - /*************************/ - - if ((devpriv->ul_TTLPortConfiguration[0] & 0xFF) - == 0xFF) { - /*****************************************************************************/ - /* Read port 2 (first digital output port) and set/reset the selected channel */ - /*****************************************************************************/ - - dw_Status = inl(devpriv->iobase + 112); - dw_Status = - (dw_Status & (0xFF - - (1 << (b_Channel - - 16)))) | - ((b_State & 1) << (b_Channel - - 16)); - outl(dw_Status, devpriv->iobase + 112); - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", - b_Channel); - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - i_ReturnValue = -3; - printk("Channel %d selection error\n", - b_Channel); - } - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| DIGITAL INPUT SUBDEVICE | -+----------------------------------------------------------------------------+ -*/ - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3XXX_InsnReadDigitalInput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Reads the value of the specified Digital input channel | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Channel = CR_CHAN(insn->chanspec) (0 to 3) | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : Channel value | -+----------------------------------------------------------------------------+ -| Return Value : 0 : No error | -| -3 : Channel selection error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI3XXX_InsnReadDigitalInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Channel = (unsigned char) CR_CHAN(insn->chanspec); - unsigned int dw_Temp = 0; - - /***************************/ - /* Test the channel number */ - /***************************/ - - if (b_Channel <= devpriv->s_EeParameters.i_NbrDiChannel) { - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - dw_Temp = inl(devpriv->iobase + 32); - *data = (dw_Temp >> b_Channel) & 1; - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - printk("Channel selection error\n"); - i_ReturnValue = -3; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3XXX_InsnBitsDigitalInput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Reads the value of the Digital input Port i.e.4channels| -+----------------------------------------------------------------------------+ -| Input Parameters : - | -+----------------------------------------------------------------------------+ -| Output Parameters : data[0] : Port value | -+----------------------------------------------------------------------------+ -| Return Value :>0: No error | -| .... | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnBitsDigitalInput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned int dw_Temp = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - dw_Temp = inl(devpriv->iobase + 32); - *data = dw_Temp & 0xf; - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| DIGITAL OUTPUT SUBDEVICE | -+----------------------------------------------------------------------------+ - -*/ - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3XXX_InsnBitsDigitalOutput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Write the selected output mask and read the status from| -| all digital output channles | -+----------------------------------------------------------------------------+ -| Input Parameters : dw_ChannelMask = data [0]; | -| dw_BitMask = data [1]; | -+----------------------------------------------------------------------------+ -| Output Parameters : data[1] : All digital output channles states | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -4 : Channel mask error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ -static int i_APCI3XXX_InsnBitsDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_ChannelCpt = 0; - unsigned int dw_ChannelMask = 0; - unsigned int dw_BitMask = 0; - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 2) { - /*******************************/ - /* Get the channe and bit mask */ - /*******************************/ - - dw_ChannelMask = data[0]; - dw_BitMask = data[1]; - - /*************************/ - /* Test the channel mask */ - /*************************/ - - if ((dw_ChannelMask & 0XFFFFFFF0) == 0) { - /*********************************/ - /* Test if set/reset any channel */ - /*********************************/ - - if (dw_ChannelMask & 0xF) { - /********************************/ - /* Read the digital output port */ - /********************************/ - - dw_Status = inl(devpriv->iobase + 48); - - for (b_ChannelCpt = 0; b_ChannelCpt < 4; - b_ChannelCpt++) { - if ((dw_ChannelMask >> b_ChannelCpt) & - 1) { - dw_Status = - (dw_Status & (0xF - - (1 << b_ChannelCpt))) | (dw_BitMask & (1 << b_ChannelCpt)); - } - } - - outl(dw_Status, devpriv->iobase + 48); - } - - /********************************/ - /* Read the digital output port */ - /********************************/ - - data[1] = inl(devpriv->iobase + 48); - } else { - /************************/ - /* Config command error */ - /************************/ - - printk("Channel mask error\n"); - i_ReturnValue = -4; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3XXX_InsnWriteDigitalOutput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Set the state from digital output channel | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Channel = CR_CHAN(insn->chanspec) | -| b_State = data [0] | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -3 : Channel selection error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI3XXX_InsnWriteDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Channel = CR_CHAN(insn->chanspec); - unsigned char b_State = 0; - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if (b_Channel < devpriv->s_EeParameters.i_NbrDoChannel) { - /*******************/ - /* Get the command */ - /*******************/ - - b_State = (unsigned char) data[0]; - - /********************************/ - /* Read the digital output port */ - /********************************/ - - dw_Status = inl(devpriv->iobase + 48); - - dw_Status = - (dw_Status & (0xF - - (1 << b_Channel))) | ((b_State & 1) << - b_Channel); - outl(dw_Status, devpriv->iobase + 48); - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - printk("Channel selection error\n"); - i_ReturnValue = -3; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function name :int i_APCI3XXX_InsnReadDigitalOutput | -| (struct comedi_device *dev, | -| struct comedi_subdevice *s, | -| struct comedi_insn *insn, | -| unsigned int *data) | -+----------------------------------------------------------------------------+ -| Task : Read the state from digital output channel | -+----------------------------------------------------------------------------+ -| Input Parameters : b_Channel = CR_CHAN(insn->chanspec) | -+----------------------------------------------------------------------------+ -| Output Parameters : b_State = data [0] | -+----------------------------------------------------------------------------+ -| Return Value : >0 : No error | -| -3 : Channel selection error | -| -101 : Data size error | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI3XXX_InsnReadDigitalOutput(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int i_ReturnValue = insn->n; - unsigned char b_Channel = CR_CHAN(insn->chanspec); - unsigned int dw_Status = 0; - - /************************/ - /* Test the buffer size */ - /************************/ - - if (insn->n >= 1) { - /***************************/ - /* Test the channel number */ - /***************************/ - - if (b_Channel < devpriv->s_EeParameters.i_NbrDoChannel) { - /********************************/ - /* Read the digital output port */ - /********************************/ - - dw_Status = inl(devpriv->iobase + 48); - - dw_Status = (dw_Status >> b_Channel) & 1; - *data = dw_Status; - } else { - /***************************/ - /* Channel selection error */ - /***************************/ - - printk("Channel selection error\n"); - i_ReturnValue = -3; - } - } else { - /*******************/ - /* Data size error */ - /*******************/ - - printk("Buffer size error\n"); - i_ReturnValue = -101; - } - - return i_ReturnValue; -} - -/* -+----------------------------------------------------------------------------+ -| Function Name : int i_APCI3XXX_Reset(struct comedi_device *dev) | +----------------------------------------------------------------------------+ -| Task :resets all the registers | -+----------------------------------------------------------------------------+ -| Input Parameters : struct comedi_device *dev | -+----------------------------------------------------------------------------+ -| Output Parameters : - | -+----------------------------------------------------------------------------+ -| Return Value : - | -+----------------------------------------------------------------------------+ -*/ - -static int i_APCI3XXX_Reset(struct comedi_device *dev) -{ - unsigned char b_Cpt = 0; - - /*************************/ - /* Disable the interrupt */ - /*************************/ - - disable_irq(dev->irq); - - /****************************/ - /* Reset the interrupt flag */ - /****************************/ - - devpriv->b_EocEosInterrupt = 0; - - /***************************/ - /* Clear the start command */ - /***************************/ - - writel(0, devpriv->dw_AiBase + 8); - - /*****************************/ - /* Reset the interrupt flags */ - /*****************************/ - - writel(readl(devpriv->dw_AiBase + 16), devpriv->dw_AiBase + 16); - - /*****************/ - /* clear the EOS */ - /*****************/ - - readl(devpriv->dw_AiBase + 20); - - /******************/ - /* Clear the FIFO */ - /******************/ - - for (b_Cpt = 0; b_Cpt < 16; b_Cpt++) { - readl(devpriv->dw_AiBase + 28); - } - - /************************/ - /* Enable the interrupt */ - /************************/ - - enable_irq(dev->irq); - - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.h b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.h deleted file mode 100644 index cce9e12e820..00000000000 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3xxx.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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. - */ - -#ifndef COMEDI_SUBD_TTLIO -#define COMEDI_SUBD_TTLIO 11 /* Digital Input Output But TTL */ -#endif - -#ifndef ADDIDATA_ENABLE -#define ADDIDATA_ENABLE 1 -#define ADDIDATA_DISABLE 0 -#endif - -#define APCI3XXX_SINGLE 0 -#define APCI3XXX_DIFF 1 -#define APCI3XXX_CONFIGURATION 0 - -#define APCI3XXX_TTL_INIT_DIRECTION_PORT2 0 - -#ifdef __KERNEL__ - -static const struct comedi_lrange range_apci3XXX_ai = { 8, {BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1)} -}; - -static const struct comedi_lrange range_apci3XXX_ttl = { 12, {BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1), - BIP_RANGE(1)} -}; - -static const struct comedi_lrange range_apci3XXX_ao = { 2, {BIP_RANGE(10), - UNI_RANGE(10)} -}; -#endif diff --git a/drivers/staging/comedi/drivers/addi_apci_035.c b/drivers/staging/comedi/drivers/addi_apci_035.c index 4c00df4bc15..4da9db35b8e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_035.c +++ b/drivers/staging/comedi/drivers/addi_apci_035.c @@ -1,11 +1,77 @@ -#define CONFIG_APCI_035 1 +#include <linux/module.h> +#include <linux/pci.h> -#define ADDIDATA_WATCHDOG 2 /* Or shold it be something else */ +#include "../comedidev.h" +#include "comedi_fc.h" +#include "amcc_s5933.h" + +#include "addi-data/addi_common.h" -#define ADDIDATA_DRIVER_NAME "addi_apci_035" +#define ADDIDATA_WATCHDOG 2 /* Or shold it be something else */ +#include "addi-data/addi_eeprom.c" +#include "addi-data/hwdrv_apci035.c" #include "addi-data/addi_common.c" +static const struct addi_board apci035_boardtypes[] = { + { + .pc_DriverName = "apci035", + .i_IorangeBase1 = APCI035_ADDRESS_RANGE, + .i_PCIEeprom = 1, + .pc_EepromChip = ADDIDATA_S5920, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 0xff, + .pr_AiRangelist = &range_apci035_ai, + .i_Timer = 1, + .ui_MinAcquisitiontimeNs = 10000, + .ui_MinDelaytimeNs = 100000, + .interrupt = apci035_interrupt, + .reset = apci035_reset, + .ai_config = apci035_ai_config, + .ai_read = apci035_ai_read, + .timer_config = apci035_timer_config, + .timer_write = apci035_timer_write, + .timer_read = apci035_timer_read, + }, +}; + +static int apci035_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + dev->board_ptr = &apci035_boardtypes[0]; + + return addi_auto_attach(dev, context); +} + +static struct comedi_driver apci035_driver = { + .driver_name = "addi_apci_035", + .module = THIS_MODULE, + .auto_attach = apci035_auto_attach, + .detach = i_ADDI_Detach, +}; + +static int apci035_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci035_driver, id->driver_data); +} + +static const struct pci_device_id apci035_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x0300) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci035_pci_table); + +static struct pci_driver apci035_pci_driver = { + .name = "addi_apci_035", + .id_table = apci035_pci_table, + .probe = apci035_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci035_driver, apci035_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c index 7831ce33b02..1b2e7c040c9 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1032.c +++ b/drivers/staging/comedi/drivers/addi_apci_1032.c @@ -1,9 +1,384 @@ -#define CONFIG_APCI_1032 1 +/* + * addi_apci_1032.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: Eric Stolz + * + * 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 ADDIDATA_DRIVER_NAME "addi_apci_1032" +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/interrupt.h> -#include "addi-data/addi_common.c" +#include "../comedidev.h" +#include "comedi_fc.h" +#include "amcc_s5933.h" + +/* + * I/O Register Map + */ +#define APCI1032_DI_REG 0x00 +#define APCI1032_MODE1_REG 0x04 +#define APCI1032_MODE2_REG 0x08 +#define APCI1032_STATUS_REG 0x0c +#define APCI1032_CTRL_REG 0x10 +#define APCI1032_CTRL_INT_OR (0 << 1) +#define APCI1032_CTRL_INT_AND (1 << 1) +#define APCI1032_CTRL_INT_ENA (1 << 2) + +struct apci1032_private { + unsigned long amcc_iobase; /* base of AMCC I/O registers */ + unsigned int mode1; /* rising-edge/high level channels */ + unsigned int mode2; /* falling-edge/low level channels */ + unsigned int ctrl; /* interrupt mode OR (edge) . AND (level) */ +}; + +static int apci1032_reset(struct comedi_device *dev) +{ + /* disable the interrupts */ + outl(0x0, dev->iobase + APCI1032_CTRL_REG); + /* Reset the interrupt status register */ + inl(dev->iobase + APCI1032_STATUS_REG); + /* Disable the and/or interrupt */ + outl(0x0, dev->iobase + APCI1032_MODE1_REG); + outl(0x0, dev->iobase + APCI1032_MODE2_REG); + + return 0; +} + +/* + * Change-Of-State (COS) interrupt configuration + * + * Channels 0 to 15 are interruptible. These channels can be configured + * to generate interrupts based on AND/OR logic for the desired channels. + * + * OR logic + * - reacts to rising or falling edges + * - interrupt is generated when any enabled channel + * meet the desired interrupt condition + * + * AND logic + * - reacts to changes in level of the selected inputs + * - interrupt is generated when all enabled channels + * meet the desired interrupt condition + * - after an interrupt, a change in level must occur on + * the selected inputs to release the IRQ logic + * + * The COS interrupt must be configured before it can be enabled. + * + * data[0] : INSN_CONFIG_DIGITAL_TRIG + * data[1] : trigger number (= 0) + * data[2] : configuration operation: + * COMEDI_DIGITAL_TRIG_DISABLE = no interrupts + * COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts + * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts + * data[3] : left-shift for data[4] and data[5] + * data[4] : rising-edge/high level channels + * data[5] : falling-edge/low level channels + */ +static int apci1032_cos_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci1032_private *devpriv = dev->private; + unsigned int shift, oldmask; + + switch (data[0]) { + case INSN_CONFIG_DIGITAL_TRIG: + if (data[1] != 0) + return -EINVAL; + shift = data[3]; + oldmask = (1U << shift) - 1; + switch (data[2]) { + case COMEDI_DIGITAL_TRIG_DISABLE: + devpriv->ctrl = 0; + devpriv->mode1 = 0; + devpriv->mode2 = 0; + apci1032_reset(dev); + break; + case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: + if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | + APCI1032_CTRL_INT_OR)) { + /* switching to 'OR' mode */ + devpriv->ctrl = APCI1032_CTRL_INT_ENA | + APCI1032_CTRL_INT_OR; + /* wipe old channels */ + devpriv->mode1 = 0; + devpriv->mode2 = 0; + } else { + /* preserve unspecified channels */ + devpriv->mode1 &= oldmask; + devpriv->mode2 &= oldmask; + } + /* configure specified channels */ + devpriv->mode1 |= data[4] << shift; + devpriv->mode2 |= data[5] << shift; + break; + case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS: + if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA | + APCI1032_CTRL_INT_AND)) { + /* switching to 'AND' mode */ + devpriv->ctrl = APCI1032_CTRL_INT_ENA | + APCI1032_CTRL_INT_AND; + /* wipe old channels */ + devpriv->mode1 = 0; + devpriv->mode2 = 0; + } else { + /* preserve unspecified channels */ + devpriv->mode1 &= oldmask; + devpriv->mode2 &= oldmask; + } + /* configure specified channels */ + devpriv->mode1 |= data[4] << shift; + devpriv->mode2 |= data[5] << shift; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return insn->n; +} + +static int apci1032_cos_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = s->state; + + return 0; +} + +static int apci1032_cos_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: ignored */ + + if (err) + return 4; + + return 0; +} + +/* + * Change-Of-State (COS) 'do_cmd' operation + * + * Enable the COS interrupt as configured by apci1032_cos_insn_config(). + */ +static int apci1032_cos_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci1032_private *devpriv = dev->private; + + if (!devpriv->ctrl) { + dev_warn(dev->class_dev, + "Interrupts disabled due to mode configuration!\n"); + return -EINVAL; + } + + outl(devpriv->mode1, dev->iobase + APCI1032_MODE1_REG); + outl(devpriv->mode2, dev->iobase + APCI1032_MODE2_REG); + outl(devpriv->ctrl, dev->iobase + APCI1032_CTRL_REG); + + return 0; +} + +static int apci1032_cos_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + return apci1032_reset(dev); +} + +static irqreturn_t apci1032_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct apci1032_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int ctrl; + + /* check interrupt is from this device */ + if ((inl(devpriv->amcc_iobase + AMCC_OP_REG_INTCSR) & + INTCSR_INTR_ASSERTED) == 0) + return IRQ_NONE; + + /* check interrupt is enabled */ + ctrl = inl(dev->iobase + APCI1032_CTRL_REG); + if ((ctrl & APCI1032_CTRL_INT_ENA) == 0) + return IRQ_HANDLED; + + /* disable the interrupt */ + outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG); + + s->state = inl(dev->iobase + APCI1032_STATUS_REG) & 0xffff; + comedi_buf_put(s, s->state); + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + comedi_event(dev, s); + + /* enable the interrupt */ + outl(ctrl, dev->iobase + APCI1032_CTRL_REG); + + return IRQ_HANDLED; +} + +static int apci1032_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inl(dev->iobase + APCI1032_DI_REG); + + return insn->n; +} + +static int apci1032_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct apci1032_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; + + devpriv->amcc_iobase = pci_resource_start(pcidev, 0); + dev->iobase = pci_resource_start(pcidev, 1); + apci1032_reset(dev); + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, apci1032_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + + /* Allocate and Initialise DI Subdevice Structures */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci1032_di_insn_bits; + + /* Change-Of-State (COS) interrupt subdevice */ + s = &dev->subdevices[1]; + 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->insn_config = apci1032_cos_insn_config; + s->insn_bits = apci1032_cos_insn_bits; + s->len_chanlist = 1; + s->do_cmdtest = apci1032_cos_cmdtest; + s->do_cmd = apci1032_cos_cmd; + s->cancel = apci1032_cos_cancel; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + return 0; +} + +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); +} + +static struct comedi_driver apci1032_driver = { + .driver_name = "addi_apci_1032", + .module = THIS_MODULE, + .auto_attach = apci1032_auto_attach, + .detach = apci1032_detach, +}; + +static int apci1032_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci1032_driver, id->driver_data); +} + +static const struct pci_device_id apci1032_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1003) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci1032_pci_table); + +static struct pci_driver apci1032_pci_driver = { + .name = "addi_apci_1032", + .id_table = apci1032_pci_table, + .probe = apci1032_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci1032_driver, apci1032_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1032, 32 channel DI boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c index bfd84f66d9c..eab75eb2647 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1500.c +++ b/drivers/staging/comedi/drivers/addi_apci_1500.c @@ -1,9 +1,76 @@ -#define CONFIG_APCI_1500 1 +#include <linux/module.h> +#include <linux/pci.h> -#define ADDIDATA_DRIVER_NAME "addi_apci_1500" +#include "../comedidev.h" +#include "comedi_fc.h" +#include "amcc_s5933.h" +#include "addi-data/addi_common.h" + +#include "addi-data/addi_eeprom.c" +#include "addi-data/hwdrv_apci1500.c" #include "addi-data/addi_common.c" +static const struct addi_board apci1500_boardtypes[] = { + { + .pc_DriverName = "apci1500", + .i_IorangeBase1 = APCI1500_ADDRESS_RANGE, + .i_PCIEeprom = ADDIDATA_NO_EEPROM, + .i_NbrDiChannel = 16, + .i_NbrDoChannel = 16, + .i_DoMaxdata = 0xffff, + .i_Timer = 1, + .interrupt = apci1500_interrupt, + .reset = apci1500_reset, + .di_config = apci1500_di_config, + .di_read = apci1500_di_read, + .di_write = apci1500_di_write, + .di_bits = apci1500_di_insn_bits, + .do_config = apci1500_do_config, + .do_write = apci1500_do_write, + .do_bits = apci1500_do_bits, + .timer_config = apci1500_timer_config, + .timer_write = apci1500_timer_write, + .timer_read = apci1500_timer_read, + .timer_bits = apci1500_timer_bits, + }, +}; + +static int apci1500_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + dev->board_ptr = &apci1500_boardtypes[0]; + + return addi_auto_attach(dev, context); +} + +static struct comedi_driver apci1500_driver = { + .driver_name = "addi_apci_1500", + .module = THIS_MODULE, + .auto_attach = apci1500_auto_attach, + .detach = i_ADDI_Detach, +}; + +static int apci1500_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci1500_driver, id->driver_data); +} + +static const struct pci_device_id apci1500_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80fc) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci1500_pci_table); + +static struct pci_driver apci1500_pci_driver = { + .name = "addi_apci_1500", + .id_table = apci1500_pci_table, + .probe = apci1500_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci1500_driver, apci1500_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1500, 16 channel DI / 16 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1516.c b/drivers/staging/comedi/drivers/addi_apci_1516.c index a12e2f42137..e9c5291c77c 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1516.c +++ b/drivers/staging/comedi/drivers/addi_apci_1516.c @@ -1,9 +1,227 @@ -#define CONFIG_APCI_1516 1 +/* + * addi_apci_1516.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: Eric Stolz + * + * 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 ADDIDATA_DRIVER_NAME "addi_apci_1516" +#include <linux/module.h> +#include <linux/pci.h> -#include "addi-data/addi_common.c" +#include "../comedidev.h" +#include "addi_watchdog.h" +#include "comedi_fc.h" +/* + * PCI bar 1 I/O Register map - Digital input/output + */ +#define APCI1516_DI_REG 0x00 +#define APCI1516_DO_REG 0x04 + +/* + * PCI bar 2 I/O Register map - Watchdog (APCI-1516 and APCI-2016) + */ +#define APCI1516_WDOG_REG 0x00 + +enum apci1516_boardid { + BOARD_APCI1016, + BOARD_APCI1516, + BOARD_APCI2016, +}; + +struct apci1516_boardinfo { + const char *name; + int di_nchan; + int do_nchan; + int has_wdog; +}; + +static const struct apci1516_boardinfo apci1516_boardtypes[] = { + [BOARD_APCI1016] = { + .name = "apci1016", + .di_nchan = 16, + }, + [BOARD_APCI1516] = { + .name = "apci1516", + .di_nchan = 8, + .do_nchan = 8, + .has_wdog = 1, + }, + [BOARD_APCI2016] = { + .name = "apci2016", + .do_nchan = 16, + .has_wdog = 1, + }, +}; + +struct apci1516_private { + unsigned long wdog_iobase; +}; + +static int apci1516_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inw(dev->iobase + APCI1516_DI_REG); + + return insn->n; +} + +static int apci1516_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + s->state = inw(dev->iobase + APCI1516_DO_REG); + + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + APCI1516_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int apci1516_reset(struct comedi_device *dev) +{ + const struct apci1516_boardinfo *this_board = comedi_board(dev); + struct apci1516_private *devpriv = dev->private; + + if (!this_board->has_wdog) + return 0; + + outw(0x0, dev->iobase + APCI1516_DO_REG); + + addi_watchdog_reset(devpriv->wdog_iobase); + + return 0; +} + +static int apci1516_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct apci1516_boardinfo *this_board = NULL; + struct apci1516_private *devpriv; + struct comedi_subdevice *s; + int ret; + + if (context < ARRAY_SIZE(apci1516_boardtypes)) + this_board = &apci1516_boardtypes[context]; + if (!this_board) + return -ENODEV; + dev->board_ptr = this_board; + 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; + + dev->iobase = pci_resource_start(pcidev, 1); + devpriv->wdog_iobase = pci_resource_start(pcidev, 2); + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + /* Initialize the digital input subdevice */ + s = &dev->subdevices[0]; + if (this_board->di_nchan) { + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = this_board->di_nchan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci1516_di_insn_bits; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Initialize the digital output subdevice */ + s = &dev->subdevices[1]; + if (this_board->do_nchan) { + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = this_board->do_nchan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci1516_do_insn_bits; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Initialize the watchdog subdevice */ + s = &dev->subdevices[2]; + if (this_board->has_wdog) { + ret = addi_watchdog_init(s, devpriv->wdog_iobase); + if (ret) + return ret; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + apci1516_reset(dev); + return 0; +} + +static void apci1516_detach(struct comedi_device *dev) +{ + if (dev->iobase) + apci1516_reset(dev); + comedi_pci_disable(dev); +} + +static struct comedi_driver apci1516_driver = { + .driver_name = "addi_apci_1516", + .module = THIS_MODULE, + .auto_attach = apci1516_auto_attach, + .detach = apci1516_detach, +}; + +static int apci1516_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci1516_driver, id->driver_data); +} + +static const struct pci_device_id apci1516_pci_table[] = { + { PCI_VDEVICE(ADDIDATA, 0x1000), BOARD_APCI1016 }, + { PCI_VDEVICE(ADDIDATA, 0x1001), BOARD_APCI1516 }, + { PCI_VDEVICE(ADDIDATA, 0x1002), BOARD_APCI2016 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci1516_pci_table); + +static struct pci_driver apci1516_pci_driver = { + .name = "addi_apci_1516", + .id_table = apci1516_pci_table, + .probe = apci1516_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci1516_driver, apci1516_pci_driver); + +MODULE_DESCRIPTION("ADDI-DATA APCI-1016/1516/2016, 16 channel DIO boards"); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1564.c b/drivers/staging/comedi/drivers/addi_apci_1564.c index 1b9d598fb6c..13d9962b47e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_1564.c +++ b/drivers/staging/comedi/drivers/addi_apci_1564.c @@ -1,9 +1,192 @@ -#define CONFIG_APCI_1564 1 +#include <linux/module.h> +#include <linux/pci.h> -#define ADDIDATA_DRIVER_NAME "addi_apci_1564" +#include "../comedidev.h" +#include "comedi_fc.h" -#include "addi-data/addi_common.c" +#include "addi-data/addi_common.h" + +#include "addi-data/hwdrv_apci1564.c" + +static irqreturn_t v_ADDI_Interrupt(int irq, void *d) +{ + apci1564_interrupt(irq, d); + return IRQ_RETVAL(1); +} + +static int apci1564_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_private *devpriv = dev->private; + + data[1] = inl(devpriv->i_IobaseAmcc + APCI1564_DI_REG); + + return insn->n; +} + +static int apci1564_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_private *devpriv = dev->private; + + s->state = inl(devpriv->i_IobaseAmcc + APCI1564_DO_REG); + + if (comedi_dio_update_state(s, data)) + outl(s->state, devpriv->i_IobaseAmcc + APCI1564_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int apci1564_reset(struct comedi_device *dev) +{ + struct addi_private *devpriv = dev->private; + + ui_Type = 0; + + /* Disable the input interrupts and reset status register */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_IRQ_REG); + inl(devpriv->i_IobaseAmcc + APCI1564_DI_INT_STATUS_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE1_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DI_INT_MODE2_REG); + + /* Reset the output channels and disable interrupts */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_DO_INT_CTRL_REG); + + /* Reset the watchdog registers */ + addi_watchdog_reset(devpriv->i_IobaseAmcc + APCI1564_WDOG_REG); + + /* Reset the timer registers */ + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_CTRL_REG); + outl(0x0, devpriv->i_IobaseAmcc + APCI1564_TIMER_RELOAD_REG); + + /* Reset the counter registers */ + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER1)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER2)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER3)); + outl(0x0, dev->iobase + APCI1564_TCW_CTRL_REG(APCI1564_COUNTER4)); + + return 0; +} + +static int apci1564_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct addi_private *devpriv; + struct comedi_subdevice *s; + int ret; + + dev->board_name = dev->driver->driver_name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 1); + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + + apci1564_reset(dev); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + /* Allocate and Initialise DI Subdevice Structures */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 32; + s->maxdata = 1; + s->len_chanlist = 32; + s->range_table = &range_digital; + s->insn_config = apci1564_di_config; + s->insn_bits = apci1564_di_insn_bits; + + /* Allocate and Initialise DO Subdevice Structures */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 32; + s->maxdata = 0xffffffff; + s->len_chanlist = 32; + s->range_table = &range_digital; + s->insn_config = apci1564_do_config; + s->insn_bits = apci1564_do_insn_bits; + s->insn_read = apci1564_do_read; + + /* Allocate and Initialise Timer Subdevice Structures */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + s->insn_write = apci1564_timer_write; + s->insn_read = apci1564_timer_read; + s->insn_config = apci1564_timer_config; + + return 0; +} + +static void apci1564_detach(struct comedi_device *dev) +{ + struct addi_private *devpriv = dev->private; + + if (devpriv) { + if (dev->iobase) + apci1564_reset(dev); + if (dev->irq) + free_irq(dev->irq, dev); + } + comedi_pci_disable(dev); +} + +static struct comedi_driver apci1564_driver = { + .driver_name = "addi_apci_1564", + .module = THIS_MODULE, + .auto_attach = apci1564_auto_attach, + .detach = apci1564_detach, +}; + +static int apci1564_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci1564_driver, id->driver_data); +} + +static const struct pci_device_id apci1564_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1006) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci1564_pci_table); + +static struct pci_driver apci1564_pci_driver = { + .name = "addi_apci_1564", + .id_table = apci1564_pci_table, + .probe = apci1564_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci1564_driver, apci1564_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-1564, 32 channel DI / 32 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_16xx.c b/drivers/staging/comedi/drivers/addi_apci_16xx.c index d54218d59c5..28df4b50b87 100644 --- a/drivers/staging/comedi/drivers/addi_apci_16xx.c +++ b/drivers/staging/comedi/drivers/addi_apci_16xx.c @@ -1,9 +1,188 @@ -#define CONFIG_APCI_16XX 1 +/* + * addi_apci_16xx.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: S. Weber + * + * 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 ADDIDATA_DRIVER_NAME "addi_apci_16xx" +#include <linux/module.h> +#include <linux/pci.h> -#include "addi-data/addi_common.c" +#include "../comedidev.h" +/* + * Register I/O map + */ +#define APCI16XX_IN_REG(x) (((x) * 4) + 0x08) +#define APCI16XX_OUT_REG(x) (((x) * 4) + 0x14) +#define APCI16XX_DIR_REG(x) (((x) * 4) + 0x20) + +enum apci16xx_boardid { + BOARD_APCI1648, + BOARD_APCI1696, +}; + +struct apci16xx_boardinfo { + const char *name; + int n_chan; +}; + +static const struct apci16xx_boardinfo apci16xx_boardtypes[] = { + [BOARD_APCI1648] = { + .name = "apci1648", + .n_chan = 48, /* 2 subdevices */ + }, + [BOARD_APCI1696] = { + .name = "apci1696", + .n_chan = 96, /* 3 subdevices */ + }, +}; + +static int apci16xx_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 8) + mask = 0x000000ff; + else if (chan < 16) + mask = 0x0000ff00; + else if (chan < 24) + mask = 0x00ff0000; + else + mask = 0xff000000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(s->index)); + + return insn->n; +} + +static int apci16xx_dio_insn_bits(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, dev->iobase + APCI16XX_OUT_REG(s->index)); + + data[1] = inl(dev->iobase + APCI16XX_IN_REG(s->index)); + + return insn->n; +} + +static int apci16xx_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct apci16xx_boardinfo *board = NULL; + struct comedi_subdevice *s; + unsigned int n_subdevs; + unsigned int last; + int i; + int ret; + + if (context < ARRAY_SIZE(apci16xx_boardtypes)) + board = &apci16xx_boardtypes[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 0); + + /* + * Work out the nubmer of subdevices needed to support all the + * digital i/o channels on the board. Each subdevice supports + * up to 32 channels. + */ + n_subdevs = board->n_chan / 32; + if ((n_subdevs * 32) < board->n_chan) { + last = board->n_chan - (n_subdevs * 32); + n_subdevs++; + } else { + last = 0; + } + + ret = comedi_alloc_subdevices(dev, n_subdevs); + if (ret) + return ret; + + /* Initialize the TTL digital i/o subdevices */ + for (i = 0; i < n_subdevs; i++) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_WRITEABLE | SDF_READABLE; + s->n_chan = ((i * 32) < board->n_chan) ? 32 : last; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = apci16xx_insn_config; + s->insn_bits = apci16xx_dio_insn_bits; + + /* Default all channels to inputs */ + s->io_bits = 0; + outl(s->io_bits, dev->iobase + APCI16XX_DIR_REG(i)); + } + + return 0; +} + +static struct comedi_driver apci16xx_driver = { + .driver_name = "addi_apci_16xx", + .module = THIS_MODULE, + .auto_attach = apci16xx_auto_attach, + .detach = comedi_pci_disable, +}; + +static int apci16xx_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci16xx_driver, id->driver_data); +} + +static const struct pci_device_id apci16xx_pci_table[] = { + { PCI_VDEVICE(ADDIDATA, 0x1009), BOARD_APCI1648 }, + { PCI_VDEVICE(ADDIDATA, 0x100a), BOARD_APCI1696 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci16xx_pci_table); + +static struct pci_driver apci16xx_pci_driver = { + .name = "addi_apci_16xx", + .id_table = apci16xx_pci_table, + .probe = apci16xx_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci16xx_driver, apci16xx_pci_driver); + +MODULE_DESCRIPTION("ADDI-DATA APCI-1648/1696, TTL I/O boards"); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_1710.c b/drivers/staging/comedi/drivers/addi_apci_1710.c deleted file mode 100644 index df6ba8ccf56..00000000000 --- a/drivers/staging/comedi/drivers/addi_apci_1710.c +++ /dev/null @@ -1,5 +0,0 @@ -#define CONFIG_APCI_1710 1 - -#define ADDIDATA_DRIVER_NAME "addi_apci_1710" - -#include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_2016.c b/drivers/staging/comedi/drivers/addi_apci_2016.c deleted file mode 100644 index fa50c7bb7ad..00000000000 --- a/drivers/staging/comedi/drivers/addi_apci_2016.c +++ /dev/null @@ -1,9 +0,0 @@ -#define CONFIG_APCI_2016 1 - -#define ADDIDATA_DRIVER_NAME "addi_apci_2016" - -#include "addi-data/addi_common.c" - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_2032.c b/drivers/staging/comedi/drivers/addi_apci_2032.c index 073a8a56dbe..be0a8a7bd3b 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2032.c +++ b/drivers/staging/comedi/drivers/addi_apci_2032.c @@ -1,9 +1,378 @@ -#define CONFIG_APCI_2032 1 +/* + * addi_apci_2032.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: Eric Stolz + * + * 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 ADDIDATA_DRIVER_NAME "addi_apci_2032" +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/slab.h> -#include "addi-data/addi_common.c" +#include "../comedidev.h" +#include "addi_watchdog.h" +#include "comedi_fc.h" + +/* + * PCI bar 1 I/O Register map + */ +#define APCI2032_DO_REG 0x00 +#define APCI2032_INT_CTRL_REG 0x04 +#define APCI2032_INT_CTRL_VCC_ENA (1 << 0) +#define APCI2032_INT_CTRL_CC_ENA (1 << 1) +#define APCI2032_INT_STATUS_REG 0x08 +#define APCI2032_INT_STATUS_VCC (1 << 0) +#define APCI2032_INT_STATUS_CC (1 << 1) +#define APCI2032_STATUS_REG 0x0c +#define APCI2032_STATUS_IRQ (1 << 0) +#define APCI2032_WDOG_REG 0x10 + +struct apci2032_int_private { + spinlock_t spinlock; + unsigned int stop_count; + bool active; + unsigned char enabled_isns; +}; + +static int apci2032_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + s->state = inl(dev->iobase + APCI2032_DO_REG); + + if (comedi_dio_update_state(s, data)) + outl(s->state, dev->iobase + APCI2032_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int apci2032_int_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inl(dev->iobase + APCI2032_INT_STATUS_REG) & 3; + return insn->n; +} + +static void apci2032_int_stop(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci2032_int_private *subpriv = s->private; + + subpriv->active = false; + subpriv->enabled_isns = 0; + 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) +{ + 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_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + 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) + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: ignored */ + + if (err) + return 4; + + return 0; +} + +static int apci2032_int_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_cmd *cmd = &s->async->cmd; + struct apci2032_int_private *subpriv = s->private; + 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); + + return 0; +} + +static int apci2032_int_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci2032_int_private *subpriv = s->private; + unsigned long flags; + + spin_lock_irqsave(&subpriv->spinlock, flags); + if (subpriv->active) + apci2032_int_stop(dev, s); + spin_unlock_irqrestore(&subpriv->spinlock, flags); + + return 0; +} + +static irqreturn_t apci2032_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + struct apci2032_int_private *subpriv; + unsigned int val; + bool do_event = false; + + if (!dev->attached) + return IRQ_NONE; + + /* Check if VCC OR CC interrupt has occurred */ + val = inl(dev->iobase + APCI2032_STATUS_REG) & APCI2032_STATUS_IRQ; + if (!val) + return IRQ_NONE; + + subpriv = s->private; + spin_lock(&subpriv->spinlock); + + val = inl(dev->iobase + APCI2032_INT_STATUS_REG) & 3; + /* Disable triggered interrupt sources. */ + outl(~val & 3, dev->iobase + APCI2032_INT_CTRL_REG); + /* + * Note: We don't reenable the triggered interrupt sources because they + * are level-sensitive, hardware error status interrupt sources and + * they'd keep triggering interrupts repeatedly. + */ + + if (subpriv->active && (val & subpriv->enabled_isns) != 0) { + unsigned short bits = 0; + int i; + + /* Bits in scan data correspond to indices in channel list. */ + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (val & (1 << chan)) + bits |= (1 << i); + } + + if (comedi_buf_put(s, bits)) { + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + if (cmd->stop_src == TRIG_COUNT && + subpriv->stop_count > 0) { + subpriv->stop_count--; + if (subpriv->stop_count == 0) { + /* end of acquisition */ + s->async->events |= COMEDI_CB_EOA; + apci2032_int_stop(dev, s); + } + } + } else { + apci2032_int_stop(dev, s); + s->async->events |= COMEDI_CB_OVERFLOW; + } + do_event = true; + } + + spin_unlock(&subpriv->spinlock); + if (do_event) + comedi_event(dev, s); + + return IRQ_HANDLED; +} + +static int apci2032_reset(struct comedi_device *dev) +{ + outl(0x0, dev->iobase + APCI2032_DO_REG); + outl(0x0, dev->iobase + APCI2032_INT_CTRL_REG); + + addi_watchdog_reset(dev->iobase + APCI2032_WDOG_REG); + + return 0; +} + +static int apci2032_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + int ret; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 1); + apci2032_reset(dev); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, apci2032_interrupt, + IRQF_SHARED, dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + /* Initialize the digital output subdevice */ + s = &dev->subdevices[0]; + 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 = apci2032_do_insn_bits; + + /* Initialize the watchdog subdevice */ + s = &dev->subdevices[1]; + ret = addi_watchdog_init(s, dev->iobase + APCI2032_WDOG_REG); + if (ret) + return ret; + + /* Initialize the interrupt subdevice */ + s = &dev->subdevices[2]; + 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 = apci2032_int_insn_bits; + if (dev->irq) { + struct apci2032_int_private *subpriv; + + dev->read_subdev = s; + subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); + if (!subpriv) + return -ENOMEM; + spin_lock_init(&subpriv->spinlock); + s->private = subpriv; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->len_chanlist = 2; + s->do_cmdtest = apci2032_int_cmdtest; + s->do_cmd = apci2032_int_cmd; + s->cancel = apci2032_int_cancel; + } + + return 0; +} + +static void apci2032_detach(struct comedi_device *dev) +{ + if (dev->iobase) + apci2032_reset(dev); + if (dev->irq) + free_irq(dev->irq, dev); + if (dev->read_subdev) + kfree(dev->read_subdev->private); + comedi_pci_disable(dev); +} + +static struct comedi_driver apci2032_driver = { + .driver_name = "addi_apci_2032", + .module = THIS_MODULE, + .auto_attach = apci2032_auto_attach, + .detach = apci2032_detach, +}; + +static int apci2032_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci2032_driver, id->driver_data); +} + +static const struct pci_device_id apci2032_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1004) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci2032_pci_table); + +static struct pci_driver apci2032_pci_driver = { + .name = "addi_apci_2032", + .id_table = apci2032_pci_table, + .probe = apci2032_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci2032_driver, apci2032_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-2032, 32 channel DO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_2200.c b/drivers/staging/comedi/drivers/addi_apci_2200.c index adfbb5d410e..e1a916546d1 100644 --- a/drivers/staging/comedi/drivers/addi_apci_2200.c +++ b/drivers/staging/comedi/drivers/addi_apci_2200.c @@ -1,9 +1,153 @@ -#define CONFIG_APCI_2200 1 +/* + * addi_apci_2200.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: Eric Stolz + * + * 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 ADDIDATA_DRIVER_NAME "addi_apci_2200" +#include <linux/module.h> +#include <linux/pci.h> -#include "addi-data/addi_common.c" +#include "../comedidev.h" +#include "addi_watchdog.h" +/* + * I/O Register Map + */ +#define APCI2200_DI_REG 0x00 +#define APCI2200_DO_REG 0x04 +#define APCI2200_WDOG_REG 0x08 + +static int apci2200_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inw(dev->iobase + APCI2200_DI_REG); + + return insn->n; +} + +static int apci2200_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + s->state = inw(dev->iobase + APCI2200_DO_REG); + + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + APCI2200_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static int apci2200_reset(struct comedi_device *dev) +{ + outw(0x0, dev->iobase + APCI2200_DO_REG); + + addi_watchdog_reset(dev->iobase + APCI2200_WDOG_REG); + + return 0; +} + +static int apci2200_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + int ret; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 1); + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + /* Initialize the digital input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci2200_di_insn_bits; + + /* Initialize the digital output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci2200_do_insn_bits; + + /* Initialize the watchdog subdevice */ + s = &dev->subdevices[2]; + ret = addi_watchdog_init(s, dev->iobase + APCI2200_WDOG_REG); + if (ret) + return ret; + + apci2200_reset(dev); + return 0; +} + +static void apci2200_detach(struct comedi_device *dev) +{ + if (dev->iobase) + apci2200_reset(dev); + comedi_pci_disable(dev); +} + +static struct comedi_driver apci2200_driver = { + .driver_name = "addi_apci_2200", + .module = THIS_MODULE, + .auto_attach = apci2200_auto_attach, + .detach = apci2200_detach, +}; + +static int apci2200_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci2200_driver, id->driver_data); +} + +static const struct pci_device_id apci2200_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1005) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci2200_pci_table); + +static struct pci_driver apci2200_pci_driver = { + .name = "addi_apci_2200", + .id_table = apci2200_pci_table, + .probe = apci2200_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci2200_driver, apci2200_pci_driver); + +MODULE_DESCRIPTION("ADDI-DATA APCI-2200 Relay board, optically isolated"); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3001.c b/drivers/staging/comedi/drivers/addi_apci_3001.c deleted file mode 100644 index 00ac762965c..00000000000 --- a/drivers/staging/comedi/drivers/addi_apci_3001.c +++ /dev/null @@ -1,9 +0,0 @@ -#define CONFIG_APCI_3001 1 - -#define ADDIDATA_DRIVER_NAME "addi_apci_3001" - -#include "addi-data/addi_common.c" - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3120.c b/drivers/staging/comedi/drivers/addi_apci_3120.c index c35515845cf..0cfb12fa1cb 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3120.c +++ b/drivers/staging/comedi/drivers/addi_apci_3120.c @@ -1,9 +1,250 @@ -#define CONFIG_APCI_3120 1 +#include <linux/module.h> +#include <linux/pci.h> -#define ADDIDATA_DRIVER_NAME "addi_apci_3120" +#include "../comedidev.h" +#include "comedi_fc.h" +#include "amcc_s5933.h" -#include "addi-data/addi_common.c" +#include "addi-data/addi_common.h" + +#include "addi-data/hwdrv_apci3120.c" + +enum apci3120_boardid { + BOARD_APCI3120, + BOARD_APCI3001, +}; + +static const struct addi_board apci3120_boardtypes[] = { + [BOARD_APCI3120] = { + .pc_DriverName = "apci3120", + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_NbrAoChannel = 8, + .i_AiMaxdata = 0xffff, + .i_AoMaxdata = 0x3fff, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 0x0f, + .interrupt = apci3120_interrupt, + }, + [BOARD_APCI3001] = { + .pc_DriverName = "apci3001", + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 0xfff, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .i_DoMaxdata = 0x0f, + .interrupt = apci3120_interrupt, + }, +}; + +static irqreturn_t v_ADDI_Interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + const struct addi_board *this_board = comedi_board(dev); + + this_board->interrupt(irq, d); + return IRQ_RETVAL(1); +} + +static int apci3120_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct addi_board *this_board = NULL; + struct addi_private *devpriv; + struct comedi_subdevice *s; + int ret, pages, i; + + if (context < ARRAY_SIZE(apci3120_boardtypes)) + this_board = &apci3120_boardtypes[context]; + if (!this_board) + return -ENODEV; + dev->board_ptr = this_board; + dev->board_name = this_board->pc_DriverName; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + pci_set_master(pcidev); + + dev->iobase = pci_resource_start(pcidev, 1); + devpriv->iobase = dev->iobase; + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2); + devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, v_ADDI_Interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + devpriv->us_UseDma = ADDI_ENABLE; + + /* Allocate DMA buffers */ + devpriv->b_DmaDoubleBuffer = 0; + for (i = 0; i < 2; i++) { + for (pages = 4; pages >= 0; pages--) { + devpriv->ul_DmaBufferVirtual[i] = + (void *) __get_free_pages(GFP_KERNEL, pages); + + 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[0]) + devpriv->us_UseDma = ADDI_DISABLE; + + if (devpriv->ul_DmaBufferVirtual[1]) + devpriv->b_DmaDoubleBuffer = 1; + + ret = comedi_alloc_subdevices(dev, 5); + if (ret) + return ret; + + /* Allocate and Initialise AI Subdevice Structures */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = + SDF_READABLE | SDF_COMMON | SDF_GROUND + | SDF_DIFF; + if (this_board->i_NbrAiChannel) { + s->n_chan = this_board->i_NbrAiChannel; + devpriv->b_SingelDiff = 0; + } else { + s->n_chan = this_board->i_NbrAiChannelDiff; + devpriv->b_SingelDiff = 1; + } + s->maxdata = this_board->i_AiMaxdata; + s->len_chanlist = this_board->i_AiChannelList; + s->range_table = &range_apci3120_ai; + + s->insn_config = apci3120_ai_insn_config; + s->insn_read = apci3120_ai_insn_read; + s->do_cmdtest = apci3120_ai_cmdtest; + s->do_cmd = apci3120_ai_cmd; + s->cancel = apci3120_cancel; + + /* Allocate and Initialise AO Subdevice Structures */ + s = &dev->subdevices[1]; + if (this_board->i_NbrAoChannel) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = this_board->i_NbrAoChannel; + s->maxdata = this_board->i_AoMaxdata; + s->len_chanlist = this_board->i_NbrAoChannel; + s->range_table = &range_apci3120_ao; + s->insn_write = apci3120_ao_insn_write; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Allocate and Initialise DI Subdevice Structures */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = this_board->i_NbrDiChannel; + s->maxdata = 1; + s->len_chanlist = this_board->i_NbrDiChannel; + s->range_table = &range_digital; + s->insn_bits = apci3120_di_insn_bits; + + /* Allocate and Initialise DO Subdevice Structures */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = + SDF_READABLE | SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = this_board->i_NbrDoChannel; + s->maxdata = this_board->i_DoMaxdata; + s->len_chanlist = this_board->i_NbrDoChannel; + s->range_table = &range_digital; + s->insn_bits = apci3120_do_insn_bits; + + /* Allocate and Initialise Timer Subdevice Structures */ + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + + s->insn_write = apci3120_write_insn_timer; + s->insn_read = apci3120_read_insn_timer; + s->insn_config = apci3120_config_insn_timer; + + apci3120_reset(dev); + return 0; +} + +static void apci3120_detach(struct comedi_device *dev) +{ + struct addi_private *devpriv = dev->private; + + 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]); + } + } + comedi_pci_disable(dev); +} + +static struct comedi_driver apci3120_driver = { + .driver_name = "addi_apci_3120", + .module = THIS_MODULE, + .auto_attach = apci3120_auto_attach, + .detach = apci3120_detach, +}; + +static int apci3120_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci3120_driver, id->driver_data); +} + +static const struct pci_device_id apci3120_pci_table[] = { + { PCI_VDEVICE(AMCC, 0x818d), BOARD_APCI3120 }, + { PCI_VDEVICE(AMCC, 0x828d), BOARD_APCI3001 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci3120_pci_table); + +static struct pci_driver apci3120_pci_driver = { + .name = "addi_apci_3120", + .id_table = apci3120_pci_table, + .probe = apci3120_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci3120_driver, apci3120_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("ADDI-DATA APCI-3120, Analog input board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3200.c b/drivers/staging/comedi/drivers/addi_apci_3200.c index 159313997dc..f0f891a482a 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3200.c +++ b/drivers/staging/comedi/drivers/addi_apci_3200.c @@ -1,5 +1,125 @@ -#define CONFIG_APCI_3200 1 +#include <linux/module.h> +#include <linux/pci.h> -#define ADDIDATA_DRIVER_NAME "addi_apci_3200" +#include <asm/i387.h> +#include "../comedidev.h" +#include "comedi_fc.h" +#include "amcc_s5933.h" + +#include "addi-data/addi_common.h" + +static void fpu_begin(void) +{ + kernel_fpu_begin(); +} + +static void fpu_end(void) +{ + kernel_fpu_end(); +} + +#include "addi-data/addi_eeprom.c" +#include "addi-data/hwdrv_apci3200.c" #include "addi-data/addi_common.c" + +enum apci3200_boardid { + BOARD_APCI3200, + BOARD_APCI3300, +}; + +static const struct addi_board apci3200_boardtypes[] = { + [BOARD_APCI3200] = { + .pc_DriverName = "apci3200", + .i_IorangeBase1 = 256, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_S5920, + .i_NbrAiChannel = 16, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 16, + .i_AiMaxdata = 0x3ffff, + .pr_AiRangelist = &range_apci3200_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .ui_MinAcquisitiontimeNs = 10000, + .ui_MinDelaytimeNs = 100000, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, + .di_bits = apci3200_di_insn_bits, + .do_bits = apci3200_do_insn_bits, + }, + [BOARD_APCI3300] = { + .pc_DriverName = "apci3300", + .i_IorangeBase1 = 256, + .i_PCIEeprom = ADDIDATA_EEPROM, + .pc_EepromChip = ADDIDATA_S5920, + .i_NbrAiChannelDiff = 8, + .i_AiChannelList = 8, + .i_AiMaxdata = 0x3ffff, + .pr_AiRangelist = &range_apci3300_ai, + .i_NbrDiChannel = 4, + .i_NbrDoChannel = 4, + .ui_MinAcquisitiontimeNs = 10000, + .ui_MinDelaytimeNs = 100000, + .interrupt = apci3200_interrupt, + .reset = apci3200_reset, + .ai_config = apci3200_ai_config, + .ai_read = apci3200_ai_read, + .ai_write = apci3200_ai_write, + .ai_bits = apci3200_ai_bits_test, + .ai_cmdtest = apci3200_ai_cmdtest, + .ai_cmd = apci3200_ai_cmd, + .ai_cancel = apci3200_cancel, + .di_bits = apci3200_di_insn_bits, + .do_bits = apci3200_do_insn_bits, + }, +}; + +static int apci3200_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + const struct addi_board *board = NULL; + + if (context < ARRAY_SIZE(apci3200_boardtypes)) + board = &apci3200_boardtypes[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + + return addi_auto_attach(dev, context); +} + +static struct comedi_driver apci3200_driver = { + .driver_name = "addi_apci_3200", + .module = THIS_MODULE, + .auto_attach = apci3200_auto_attach, + .detach = i_ADDI_Detach, +}; + +static int apci3200_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci3200_driver, id->driver_data); +} + +static const struct pci_device_id apci3200_pci_table[] = { + { PCI_VDEVICE(ADDIDATA, 0x3000), BOARD_APCI3200 }, + { PCI_VDEVICE(ADDIDATA, 0x3007), BOARD_APCI3300 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci3200_pci_table); + +static struct pci_driver apci3200_pci_driver = { + .name = "addi_apci_3200", + .id_table = apci3200_pci_table, + .probe = apci3200_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci3200_driver, apci3200_pci_driver); diff --git a/drivers/staging/comedi/drivers/addi_apci_3300.c b/drivers/staging/comedi/drivers/addi_apci_3300.c deleted file mode 100644 index 733c69abc43..00000000000 --- a/drivers/staging/comedi/drivers/addi_apci_3300.c +++ /dev/null @@ -1,5 +0,0 @@ -#define CONFIG_APCI_3300 1 - -#define ADDIDATA_DRIVER_NAME "addi_apci_3300" - -#include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c index dd2c1d3bc18..49bf1fb840f 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3501.c +++ b/drivers/staging/comedi/drivers/addi_apci_3501.c @@ -1,9 +1,447 @@ -#define CONFIG_APCI_3501 1 +/* + * addi_apci_3501.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: Eric Stolz + * + * 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 ADDIDATA_DRIVER_NAME "addi_apci_3501" +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/sched.h> -#include "addi-data/addi_common.c" +#include "../comedidev.h" +#include "comedi_fc.h" +#include "amcc_s5933.h" +/* + * PCI bar 1 register I/O map + */ +#define APCI3501_AO_CTRL_STATUS_REG 0x00 +#define APCI3501_AO_CTRL_BIPOLAR (1 << 0) +#define APCI3501_AO_STATUS_READY (1 << 8) +#define APCI3501_AO_DATA_REG 0x04 +#define APCI3501_AO_DATA_CHAN(x) ((x) << 0) +#define APCI3501_AO_DATA_VAL(x) ((x) << 8) +#define APCI3501_AO_DATA_BIPOLAR (1 << 31) +#define APCI3501_AO_TRIG_SCS_REG 0x08 +#define APCI3501_TIMER_SYNC_REG 0x20 +#define APCI3501_TIMER_RELOAD_REG 0x24 +#define APCI3501_TIMER_TIMEBASE_REG 0x28 +#define APCI3501_TIMER_CTRL_REG 0x2c +#define APCI3501_TIMER_STATUS_REG 0x30 +#define APCI3501_TIMER_IRQ_REG 0x34 +#define APCI3501_TIMER_WARN_RELOAD_REG 0x38 +#define APCI3501_TIMER_WARN_TIMEBASE_REG 0x3c +#define APCI3501_DO_REG 0x40 +#define APCI3501_DI_REG 0x50 + +/* + * AMCC S5933 NVRAM + */ +#define NVRAM_USER_DATA_START 0x100 + +#define NVCMD_BEGIN_READ (0x7 << 5) +#define NVCMD_LOAD_LOW (0x4 << 5) +#define NVCMD_LOAD_HIGH (0x5 << 5) + +/* + * Function types stored in the eeprom + */ +#define EEPROM_DIGITALINPUT 0 +#define EEPROM_DIGITALOUTPUT 1 +#define EEPROM_ANALOGINPUT 2 +#define EEPROM_ANALOGOUTPUT 3 +#define EEPROM_TIMER 4 +#define EEPROM_WATCHDOG 5 +#define EEPROM_TIMER_WATCHDOG_COUNTER 10 + +struct apci3501_private { + int i_IobaseAmcc; + struct task_struct *tsk_Current; + unsigned char b_TimerSelectMode; +}; + +static struct comedi_lrange apci3501_ao_range = { + 2, { + BIP_RANGE(10), + UNI_RANGE(10) + } +}; + +static int apci3501_wait_for_dac(struct comedi_device *dev) +{ + unsigned int status; + + do { + status = inl(dev->iobase + APCI3501_AO_CTRL_STATUS_REG); + } while (!(status & APCI3501_AO_STATUS_READY)); + + return 0; +} + +static int apci3501_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 = 0; + int i; + int ret; + + /* + * All analog output channels have the same output range. + * 14-bit bipolar: 0-10V + * 13-bit unipolar: +/-10V + * Changing the range of one channel changes all of them! + */ + if (range) { + outl(0, dev->iobase + APCI3501_AO_CTRL_STATUS_REG); + } else { + val |= 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++) { + if (range == 1) { + if (data[i] > 0x1fff) { + dev_err(dev->class_dev, + "Unipolar resolution is only 13-bits\n"); + return -EINVAL; + } + } + + ret = apci3501_wait_for_dac(dev); + if (ret) + return ret; + + outl(val | APCI3501_AO_DATA_VAL(data[i]), + dev->iobase + APCI3501_AO_DATA_REG); + } + + return insn->n; +} + +#include "addi-data/hwdrv_apci3501.c" + +static int apci3501_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inl(dev->iobase + APCI3501_DI_REG) & 0x3; + + return insn->n; +} + +static int apci3501_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + s->state = inl(dev->iobase + APCI3501_DO_REG); + + if (comedi_dio_update_state(s, data)) + outl(s->state, dev->iobase + APCI3501_DO_REG); + + data[1] = s->state; + + return insn->n; +} + +static void apci3501_eeprom_wait(unsigned long iobase) +{ + unsigned char val; + + do { + val = inb(iobase + AMCC_OP_REG_MCSR_NVCMD); + } while (val & 0x80); +} + +static unsigned short apci3501_eeprom_readw(unsigned long iobase, + unsigned short addr) +{ + unsigned short val = 0; + unsigned char tmp; + unsigned char i; + + /* Add the offset to the start of the user data */ + addr += NVRAM_USER_DATA_START; + + for (i = 0; i < 2; i++) { + /* Load the low 8 bit address */ + outb(NVCMD_LOAD_LOW, iobase + AMCC_OP_REG_MCSR_NVCMD); + apci3501_eeprom_wait(iobase); + outb((addr + i) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); + apci3501_eeprom_wait(iobase); + + /* Load the high 8 bit address */ + outb(NVCMD_LOAD_HIGH, iobase + AMCC_OP_REG_MCSR_NVCMD); + apci3501_eeprom_wait(iobase); + outb(((addr + i) >> 8) & 0xff, + iobase + AMCC_OP_REG_MCSR_NVDATA); + apci3501_eeprom_wait(iobase); + + /* Read the eeprom data byte */ + outb(NVCMD_BEGIN_READ, iobase + AMCC_OP_REG_MCSR_NVCMD); + apci3501_eeprom_wait(iobase); + tmp = inb(iobase + AMCC_OP_REG_MCSR_NVDATA); + apci3501_eeprom_wait(iobase); + + if (i == 0) + val |= tmp; + else + val |= (tmp << 8); + } + + return val; +} + +static int apci3501_eeprom_get_ao_n_chan(struct comedi_device *dev) +{ + struct apci3501_private *devpriv = dev->private; + unsigned long iobase = devpriv->i_IobaseAmcc; + unsigned char nfuncs; + int i; + + nfuncs = apci3501_eeprom_readw(iobase, 10) & 0xff; + + /* Read functionality details */ + for (i = 0; i < nfuncs; i++) { + unsigned short offset = i * 4; + unsigned short addr; + unsigned char func; + unsigned short val; + + func = apci3501_eeprom_readw(iobase, 12 + offset) & 0x3f; + addr = apci3501_eeprom_readw(iobase, 14 + offset); + + if (func == EEPROM_ANALOGOUTPUT) { + val = apci3501_eeprom_readw(iobase, addr + 10); + return (val >> 4) & 0x3ff; + } + } + return 0; +} + +static int apci3501_eeprom_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3501_private *devpriv = dev->private; + unsigned short addr = CR_CHAN(insn->chanspec); + + data[0] = apci3501_eeprom_readw(devpriv->i_IobaseAmcc, 2 * addr); + + return insn->n; +} + +static irqreturn_t apci3501_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct apci3501_private *devpriv = dev->private; + unsigned int ui_Timer_AOWatchdog; + unsigned long ul_Command1; + int i_temp; + + /* Disable Interrupt */ + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); + ul_Command1 = (ul_Command1 & 0xFFFFF9FDul); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + + ui_Timer_AOWatchdog = inl(dev->iobase + APCI3501_TIMER_IRQ_REG) & 0x1; + if ((!ui_Timer_AOWatchdog)) { + comedi_error(dev, "IRQ from unknown source"); + return IRQ_NONE; + } + + /* Enable Interrupt Send a signal to from kernel to user space */ + send_sig(SIGIO, devpriv->tsk_Current, 0); + ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG); + ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1); + outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG); + i_temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1; + + return IRQ_HANDLED; +} + +static int apci3501_reset(struct comedi_device *dev) +{ + unsigned int val; + int chan; + int ret; + + /* Reset all digital outputs to "0" */ + outl(0x0, dev->iobase + APCI3501_DO_REG); + + /* Default all analog outputs to 0V (bipolar) */ + outl(APCI3501_AO_CTRL_BIPOLAR, + dev->iobase + APCI3501_AO_CTRL_STATUS_REG); + val = APCI3501_AO_DATA_BIPOLAR | APCI3501_AO_DATA_VAL(0); + + /* Set all analog output channels */ + for (chan = 0; chan < 8; chan++) { + ret = apci3501_wait_for_dac(dev); + if (ret) { + dev_warn(dev->class_dev, + "%s: DAC not-ready for channel %i\n", + __func__, chan); + } else { + outl(val | APCI3501_AO_DATA_CHAN(chan), + dev->iobase + APCI3501_AO_DATA_REG); + } + } + + return 0; +} + +static int apci3501_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct apci3501_private *devpriv; + struct comedi_subdevice *s; + int ao_n_chan; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 1); + devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0); + + ao_n_chan = apci3501_eeprom_get_ao_n_chan(dev); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, apci3501_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + ret = comedi_alloc_subdevices(dev, 5); + if (ret) + return ret; + + /* Initialize the analog output subdevice */ + s = &dev->subdevices[0]; + if (ao_n_chan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = ao_n_chan; + s->maxdata = 0x3fff; + s->range_table = &apci3501_ao_range; + s->insn_write = apci3501_ao_insn_write; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* Initialize the digital input subdevice */ + s = &dev->subdevices[1]; + 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 = apci3501_di_insn_bits; + + /* Initialize the digital output subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci3501_do_insn_bits; + + /* Initialize the timer/watchdog subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 1; + s->maxdata = 0; + s->len_chanlist = 1; + s->range_table = &range_digital; + s->insn_write = apci3501_write_insn_timer; + s->insn_read = apci3501_read_insn_timer; + s->insn_config = apci3501_config_insn_timer; + + /* Initialize the eeprom subdevice */ + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE | SDF_INTERNAL; + s->n_chan = 256; + s->maxdata = 0xffff; + s->insn_read = apci3501_eeprom_insn_read; + + apci3501_reset(dev); + return 0; +} + +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); +} + +static struct comedi_driver apci3501_driver = { + .driver_name = "addi_apci_3501", + .module = THIS_MODULE, + .auto_attach = apci3501_auto_attach, + .detach = apci3501_detach, +}; + +static int apci3501_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci3501_driver, id->driver_data); +} + +static const struct pci_device_id apci3501_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x3001) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci3501_pci_table); + +static struct pci_driver apci3501_pci_driver = { + .name = "addi_apci_3501", + .id_table = apci3501_pci_table, + .probe = apci3501_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci3501_driver, apci3501_pci_driver); + +MODULE_DESCRIPTION("ADDI-DATA APCI-3501 Analog output board"); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_apci_3xxx.c b/drivers/staging/comedi/drivers/addi_apci_3xxx.c index 03161c88eac..0532b6cc40e 100644 --- a/drivers/staging/comedi/drivers/addi_apci_3xxx.c +++ b/drivers/staging/comedi/drivers/addi_apci_3xxx.c @@ -1,8 +1,981 @@ -#define CONFIG_APCI_3XXX 1 +/* + * addi_apci_3xxx.c + * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. + * Project manager: S. Weber + * + * 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 ADDIDATA_DRIVER_NAME "addi_apci_3xxx" +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/interrupt.h> -#include "addi-data/addi_common.c" +#include "../comedidev.h" + +#include "comedi_fc.h" + +#define CONV_UNIT_NS (1 << 0) +#define CONV_UNIT_US (1 << 1) +#define CONV_UNIT_MS (1 << 2) + +static const struct comedi_lrange apci3xxx_ai_range = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1) + } +}; + +static const struct comedi_lrange apci3xxx_ao_range = { + 2, { + BIP_RANGE(10), + UNI_RANGE(10) + } +}; + +enum apci3xxx_boardid { + BOARD_APCI3000_16, + BOARD_APCI3000_8, + BOARD_APCI3000_4, + BOARD_APCI3006_16, + BOARD_APCI3006_8, + BOARD_APCI3006_4, + BOARD_APCI3010_16, + BOARD_APCI3010_8, + BOARD_APCI3010_4, + BOARD_APCI3016_16, + BOARD_APCI3016_8, + BOARD_APCI3016_4, + BOARD_APCI3100_16_4, + BOARD_APCI3100_8_4, + BOARD_APCI3106_16_4, + BOARD_APCI3106_8_4, + BOARD_APCI3110_16_4, + BOARD_APCI3110_8_4, + BOARD_APCI3116_16_4, + BOARD_APCI3116_8_4, + BOARD_APCI3003, + BOARD_APCI3002_16, + BOARD_APCI3002_8, + BOARD_APCI3002_4, + BOARD_APCI3500, +}; + +struct apci3xxx_boardinfo { + const char *name; + int ai_subdev_flags; + int ai_n_chan; + unsigned int ai_maxdata; + unsigned char ai_conv_units; + unsigned int ai_min_acq_ns; + unsigned int has_ao:1; + unsigned int has_dig_in:1; + unsigned int has_dig_out:1; + unsigned int has_ttl_io:1; +}; + +static const struct apci3xxx_boardinfo apci3xxx_boardtypes[] = { + [BOARD_APCI3000_16] = { + .name = "apci3000-16", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, + }, + [BOARD_APCI3000_8] = { + .name = "apci3000-8", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, + }, + [BOARD_APCI3000_4] = { + .name = "apci3000-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, + }, + [BOARD_APCI3006_16] = { + .name = "apci3006-16", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, + }, + [BOARD_APCI3006_8] = { + .name = "apci3006-8", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, + }, + [BOARD_APCI3006_4] = { + .name = "apci3006-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ttl_io = 1, + }, + [BOARD_APCI3010_16] = { + .name = "apci3010-16", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3010_8] = { + .name = "apci3010-8", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3010_4] = { + .name = "apci3010-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3016_16] = { + .name = "apci3016-16", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3016_8] = { + .name = "apci3016-8", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3016_4] = { + .name = "apci3016-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3100_16_4] = { + .name = "apci3100-16-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ao = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3100_8_4] = { + .name = "apci3100-8-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ao = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3106_16_4] = { + .name = "apci3106-16-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ao = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3106_8_4] = { + .name = "apci3106-8-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 10000, + .has_ao = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3110_16_4] = { + .name = "apci3110-16-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_ao = 1, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3110_8_4] = { + .name = "apci3110-8-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0x0fff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_ao = 1, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3116_16_4] = { + .name = "apci3116-16-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_ao = 1, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3116_8_4] = { + .name = "apci3116-8-4", + .ai_subdev_flags = SDF_COMMON | SDF_GROUND | SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_ao = 1, + .has_dig_in = 1, + .has_dig_out = 1, + .has_ttl_io = 1, + }, + [BOARD_APCI3003] = { + .name = "apci3003", + .ai_subdev_flags = SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US | + CONV_UNIT_NS, + .ai_min_acq_ns = 2500, + .has_dig_in = 1, + .has_dig_out = 1, + }, + [BOARD_APCI3002_16] = { + .name = "apci3002-16", + .ai_subdev_flags = SDF_DIFF, + .ai_n_chan = 16, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + }, + [BOARD_APCI3002_8] = { + .name = "apci3002-8", + .ai_subdev_flags = SDF_DIFF, + .ai_n_chan = 8, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + }, + [BOARD_APCI3002_4] = { + .name = "apci3002-4", + .ai_subdev_flags = SDF_DIFF, + .ai_n_chan = 4, + .ai_maxdata = 0xffff, + .ai_conv_units = CONV_UNIT_MS | CONV_UNIT_US, + .ai_min_acq_ns = 5000, + .has_dig_in = 1, + .has_dig_out = 1, + }, + [BOARD_APCI3500] = { + .name = "apci3500", + .has_ao = 1, + .has_ttl_io = 1, + }, +}; + +struct apci3xxx_private { + void __iomem *mmio; + unsigned int ai_timer; + unsigned char ai_time_base; +}; + +static irqreturn_t apci3xxx_irq_handler(int irq, void *d) +{ + struct comedi_device *dev = d; + struct apci3xxx_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int status; + unsigned int val; + + /* Test if interrupt occur */ + status = readl(devpriv->mmio + 16); + if ((status & 0x2) == 0x2) { + /* Reset the interrupt */ + writel(status, devpriv->mmio + 16); + + val = readl(devpriv->mmio + 28); + comedi_buf_put(s, val); + + s->async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); + + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int apci3xxx_ai_started(struct comedi_device *dev) +{ + struct apci3xxx_private *devpriv = dev->private; + + if ((readl(devpriv->mmio + 8) & 0x80000) == 0x80000) + return 1; + else + return 0; + +} + +static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int delay_mode; + unsigned int val; + + if (apci3xxx_ai_started(dev)) + return -EBUSY; + + /* Clear the FIFO */ + writel(0x10000, devpriv->mmio + 12); + + /* Get and save the delay mode */ + delay_mode = readl(devpriv->mmio + 4); + delay_mode &= 0xfffffef0; + + /* Channel configuration selection */ + writel(delay_mode, devpriv->mmio + 4); + + /* Make the configuration */ + val = (range & 3) | ((range >> 2) << 6) | + ((aref == AREF_DIFF) << 7); + writel(val, devpriv->mmio + 0); + + /* Channel selection */ + writel(delay_mode | 0x100, devpriv->mmio + 4); + writel(chan, devpriv->mmio + 0); + + /* Restore delay mode */ + writel(delay_mode, devpriv->mmio + 4); + + /* Set the number of sequence to 1 */ + writel(1, devpriv->mmio + 48); + + return 0; +} + +static int apci3xxx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 20); + if (status & 0x1) + return 0; + return -EBUSY; +} + +static int apci3xxx_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3xxx_private *devpriv = dev->private; + int ret; + int i; + + ret = apci3xxx_ai_setup(dev, insn->chanspec); + if (ret) + return ret; + + for (i = 0; i < insn->n; i++) { + /* Start the conversion */ + writel(0x80000, devpriv->mmio + 8); + + /* Wait the EOS */ + ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0); + if (ret) + return ret; + + /* Read the analog value */ + data[i] = readl(devpriv->mmio + 28); + } + + return insn->n; +} + +static int apci3xxx_ai_ns_to_timer(struct comedi_device *dev, + unsigned int *ns, int round_mode) +{ + const struct apci3xxx_boardinfo *board = comedi_board(dev); + struct apci3xxx_private *devpriv = dev->private; + unsigned int base; + unsigned int timer; + int time_base; + + /* time_base: 0 = ns, 1 = us, 2 = ms */ + for (time_base = 0; time_base < 3; time_base++) { + /* skip unsupported time bases */ + if (!(board->ai_conv_units & (1 << time_base))) + continue; + + switch (time_base) { + case 0: + base = 1; + break; + case 1: + base = 1000; + break; + case 2: + base = 1000000; + break; + } + + switch (round_mode) { + case TRIG_ROUND_NEAREST: + default: + timer = (*ns + base / 2) / base; + break; + case TRIG_ROUND_DOWN: + timer = *ns / base; + break; + case TRIG_ROUND_UP: + timer = (*ns + base - 1) / base; + break; + } + + if (timer < 0x10000) { + devpriv->ai_time_base = time_base; + devpriv->ai_timer = timer; + *ns = timer * time_base; + return 0; + } + } + return -EINVAL; +} + +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); + 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_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + board->ai_min_acq_ns); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + arg = cmd->convert_arg; + err |= apci3xxx_ai_ns_to_timer(dev, &arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (err) + return 4; + + return 0; +} + +static int apci3xxx_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct apci3xxx_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; + + ret = apci3xxx_ai_setup(dev, cmd->chanlist[0]); + if (ret) + return ret; + + /* Set the convert timing unit */ + writel(devpriv->ai_time_base, devpriv->mmio + 36); + + /* Set the convert timing */ + writel(devpriv->ai_timer, devpriv->mmio + 32); + + /* Start the conversion */ + writel(0x180000, devpriv->mmio + 8); + + return 0; +} + +static int apci3xxx_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + return 0; +} + +static int apci3xxx_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->mmio + 96); + if (status & 0x100) + return 0; + return -EBUSY; +} + +static int apci3xxx_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret; + int i; + + for (i = 0; i < insn->n; i++) { + /* Set the range selection */ + writel(range, devpriv->mmio + 96); + + /* Write the analog value to the selected channel */ + writel((data[i] << 8) | chan, devpriv->mmio + 100); + + /* Wait the end of transfer */ + ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0); + if (ret) + return ret; + } + + return insn->n; +} + +static int apci3xxx_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inl(dev->iobase + 32) & 0xf; + + return insn->n; +} + +static int apci3xxx_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + s->state = inl(dev->iobase + 48) & 0xf; + + if (comedi_dio_update_state(s, data)) + outl(s->state, dev->iobase + 48); + + data[1] = s->state; + + return insn->n; +} + +static int apci3xxx_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask = 0; + int ret; + + /* + * Port 0 (channels 0-7) are always inputs + * Port 1 (channels 8-15) are always outputs + * Port 2 (channels 16-23) are programmable i/o + */ + if (data[0] != INSN_CONFIG_DIO_QUERY) { + /* ignore all other instructions for ports 0 and 1 */ + if (chan < 16) + return -EINVAL; + else + /* changing any channel in port 2 */ + /* changes the entire port */ + mask = 0xff0000; + } + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + /* update port 2 configuration */ + outl((s->io_bits >> 24) & 0xff, dev->iobase + 224); + + return insn->n; +} + +static int apci3xxx_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0xff) + outl(s->state & 0xff, dev->iobase + 80); + if (mask & 0xff0000) + outl((s->state >> 16) & 0xff, dev->iobase + 112); + } + + val = inl(dev->iobase + 80); + val |= (inl(dev->iobase + 64) << 8); + if (s->io_bits & 0xff0000) + val |= (inl(dev->iobase + 112) << 16); + else + val |= (inl(dev->iobase + 96) << 16); + + data[1] = val; + + return insn->n; +} + +static int apci3xxx_reset(struct comedi_device *dev) +{ + struct apci3xxx_private *devpriv = dev->private; + unsigned int val; + int i; + + /* Disable the interrupt */ + disable_irq(dev->irq); + + /* Clear the start command */ + writel(0, devpriv->mmio + 8); + + /* Reset the interrupt flags */ + val = readl(devpriv->mmio + 16); + writel(val, devpriv->mmio + 16); + + /* clear the EOS */ + readl(devpriv->mmio + 20); + + /* Clear the FIFO */ + for (i = 0; i < 16; i++) + val = readl(devpriv->mmio + 28); + + /* Enable the interrupt */ + enable_irq(dev->irq); + + return 0; +} + +static int apci3xxx_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct apci3xxx_boardinfo *board = NULL; + struct apci3xxx_private *devpriv; + struct comedi_subdevice *s; + int n_subdevices; + int subdev; + int ret; + + if (context < ARRAY_SIZE(apci3xxx_boardtypes)) + board = &apci3xxx_boardtypes[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 2); + devpriv->mmio = pci_ioremap_bar(pcidev, 3); + + if (pcidev->irq > 0) { + ret = request_irq(pcidev->irq, apci3xxx_irq_handler, + IRQF_SHARED, dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + n_subdevices = (board->ai_n_chan ? 0 : 1) + board->has_ao + + board->has_dig_in + board->has_dig_out + + board->has_ttl_io; + ret = comedi_alloc_subdevices(dev, n_subdevices); + if (ret) + return ret; + + subdev = 0; + + /* Analog Input subdevice */ + if (board->ai_n_chan) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | board->ai_subdev_flags; + s->n_chan = board->ai_n_chan; + s->maxdata = board->ai_maxdata; + s->range_table = &apci3xxx_ai_range; + s->insn_read = apci3xxx_ai_insn_read; + if (dev->irq) { + /* + * FIXME: The hardware supports multiple scan modes + * but the original addi-data driver only supported + * reading a single channel with interrupts. Need a + * proper datasheet to fix this. + * + * The following scan modes are supported by the + * hardware: + * 1) Single software scan + * 2) Single hardware triggered scan + * 3) Continuous software scan + * 4) Continuous software scan with timer delay + * 5) Continuous hardware triggered scan + * 6) Continuous hardware triggered scan with timer + * delay + * + * For now, limit the chanlist to a single channel. + */ + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; + s->do_cmdtest = apci3xxx_ai_cmdtest; + s->do_cmd = apci3xxx_ai_cmd; + s->cancel = apci3xxx_ai_cancel; + } + + subdev++; + } + + /* Analog Output subdevice */ + if (board->has_ao) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 4; + s->maxdata = 0x0fff; + s->range_table = &apci3xxx_ao_range; + s->insn_write = apci3xxx_ao_insn_write; + + subdev++; + } + + /* Digital Input subdevice */ + if (board->has_dig_in) { + s = &dev->subdevices[subdev]; + 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 = apci3xxx_di_insn_bits; + + subdev++; + } + + /* Digital Output subdevice */ + if (board->has_dig_out) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = apci3xxx_do_insn_bits; + + subdev++; + } + + /* TTL Digital I/O subdevice */ + if (board->has_ttl_io) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->n_chan = 24; + s->maxdata = 1; + s->io_bits = 0xff; /* channels 0-7 are always outputs */ + s->range_table = &range_digital; + s->insn_config = apci3xxx_dio_insn_config; + s->insn_bits = apci3xxx_dio_insn_bits; + + subdev++; + } + + apci3xxx_reset(dev); + return 0; +} + +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 (devpriv->mmio) + iounmap(devpriv->mmio); + } + comedi_pci_disable(dev); +} + +static struct comedi_driver apci3xxx_driver = { + .driver_name = "addi_apci_3xxx", + .module = THIS_MODULE, + .auto_attach = apci3xxx_auto_attach, + .detach = apci3xxx_detach, +}; + +static int apci3xxx_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &apci3xxx_driver, id->driver_data); +} + +static const struct pci_device_id apci3xxx_pci_table[] = { + { PCI_VDEVICE(ADDIDATA, 0x3010), BOARD_APCI3000_16 }, + { PCI_VDEVICE(ADDIDATA, 0x300f), BOARD_APCI3000_8 }, + { PCI_VDEVICE(ADDIDATA, 0x300e), BOARD_APCI3000_4 }, + { PCI_VDEVICE(ADDIDATA, 0x3013), BOARD_APCI3006_16 }, + { PCI_VDEVICE(ADDIDATA, 0x3014), BOARD_APCI3006_8 }, + { PCI_VDEVICE(ADDIDATA, 0x3015), BOARD_APCI3006_4 }, + { PCI_VDEVICE(ADDIDATA, 0x3016), BOARD_APCI3010_16 }, + { PCI_VDEVICE(ADDIDATA, 0x3017), BOARD_APCI3010_8 }, + { PCI_VDEVICE(ADDIDATA, 0x3018), BOARD_APCI3010_4 }, + { PCI_VDEVICE(ADDIDATA, 0x3019), BOARD_APCI3016_16 }, + { PCI_VDEVICE(ADDIDATA, 0x301a), BOARD_APCI3016_8 }, + { PCI_VDEVICE(ADDIDATA, 0x301b), BOARD_APCI3016_4 }, + { PCI_VDEVICE(ADDIDATA, 0x301c), BOARD_APCI3100_16_4 }, + { PCI_VDEVICE(ADDIDATA, 0x301d), BOARD_APCI3100_8_4 }, + { PCI_VDEVICE(ADDIDATA, 0x301e), BOARD_APCI3106_16_4 }, + { PCI_VDEVICE(ADDIDATA, 0x301f), BOARD_APCI3106_8_4 }, + { PCI_VDEVICE(ADDIDATA, 0x3020), BOARD_APCI3110_16_4 }, + { PCI_VDEVICE(ADDIDATA, 0x3021), BOARD_APCI3110_8_4 }, + { PCI_VDEVICE(ADDIDATA, 0x3022), BOARD_APCI3116_16_4 }, + { PCI_VDEVICE(ADDIDATA, 0x3023), BOARD_APCI3116_8_4 }, + { PCI_VDEVICE(ADDIDATA, 0x300B), BOARD_APCI3003 }, + { PCI_VDEVICE(ADDIDATA, 0x3002), BOARD_APCI3002_16 }, + { PCI_VDEVICE(ADDIDATA, 0x3003), BOARD_APCI3002_8 }, + { PCI_VDEVICE(ADDIDATA, 0x3004), BOARD_APCI3002_4 }, + { PCI_VDEVICE(ADDIDATA, 0x3024), BOARD_APCI3500 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, apci3xxx_pci_table); + +static struct pci_driver apci3xxx_pci_driver = { + .name = "addi_apci_3xxx", + .id_table = apci3xxx_pci_table, + .probe = apci3xxx_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(apci3xxx_driver, apci3xxx_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/addi_apci_all.c b/drivers/staging/comedi/drivers/addi_apci_all.c deleted file mode 100644 index aeb1b2688f3..00000000000 --- a/drivers/staging/comedi/drivers/addi_apci_all.c +++ /dev/null @@ -1,18 +0,0 @@ -#define CONFIG_APCI_035 1 -#define CONFIG_APCI_1032 1 -#define CONFIG_APCI_1500 1 -#define CONFIG_APCI_1516 1 -#define CONFIG_APCI_1564 1 -#define CONFIG_APCI_16XX 1 -#define CONFIG_APCI_1710 1 -#define CONFIG_APCI_2016 1 -#define CONFIG_APCI_2032 1 -#define CONFIG_APCI_2200 1 -#define CONFIG_APCI_3001 1 -#define CONFIG_APCI_3120 1 -#define CONFIG_APCI_3200 1 -#define CONFIG_APCI_3300 1 -#define CONFIG_APCI_3501 1 -#define CONFIG_APCI_3XXX 1 - -#include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/addi_watchdog.c b/drivers/staging/comedi/drivers/addi_watchdog.c new file mode 100644 index 00000000000..23031feaa09 --- /dev/null +++ b/drivers/staging/comedi/drivers/addi_watchdog.c @@ -0,0 +1,161 @@ +/* + * COMEDI driver for the watchdog subdevice found on some addi-data boards + * Copyright (c) 2013 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on implementations in various addi-data COMEDI drivers. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include "../comedidev.h" +#include "addi_watchdog.h" + +/* + * Register offsets/defines for the addi-data watchdog + */ +#define ADDI_WDOG_REG 0x00 +#define ADDI_WDOG_RELOAD_REG 0x04 +#define ADDI_WDOG_TIMEBASE 0x08 +#define ADDI_WDOG_CTRL_REG 0x0c +#define ADDI_WDOG_CTRL_ENABLE (1 << 0) +#define ADDI_WDOG_CTRL_SW_TRIG (1 << 9) +#define ADDI_WDOG_STATUS_REG 0x10 +#define ADDI_WDOG_STATUS_ENABLED (1 << 0) +#define ADDI_WDOG_STATUS_SW_TRIG (1 << 1) + +struct addi_watchdog_private { + unsigned long iobase; + unsigned int wdog_ctrl; +}; + +/* + * The watchdog subdevice is configured with two INSN_CONFIG instructions: + * + * Enable the watchdog and set the reload timeout: + * data[0] = INSN_CONFIG_ARM + * data[1] = timeout reload value + * + * Disable the watchdog: + * data[0] = INSN_CONFIG_DISARM + */ +static int addi_watchdog_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_watchdog_private *spriv = s->private; + unsigned int reload; + + switch (data[0]) { + case INSN_CONFIG_ARM: + spriv->wdog_ctrl = ADDI_WDOG_CTRL_ENABLE; + reload = data[1] & s->maxdata; + outl(reload, spriv->iobase + ADDI_WDOG_RELOAD_REG); + + /* Time base is 20ms, let the user know the timeout */ + dev_info(dev->class_dev, "watchdog enabled, timeout:%dms\n", + 20 * reload + 20); + break; + case INSN_CONFIG_DISARM: + spriv->wdog_ctrl = 0; + break; + default: + return -EINVAL; + } + + outl(spriv->wdog_ctrl, spriv->iobase + ADDI_WDOG_CTRL_REG); + + return insn->n; +} + +static int addi_watchdog_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_watchdog_private *spriv = s->private; + int i; + + for (i = 0; i < insn->n; i++) + data[i] = inl(spriv->iobase + ADDI_WDOG_STATUS_REG); + + return insn->n; +} + +static int addi_watchdog_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct addi_watchdog_private *spriv = s->private; + int i; + + if (spriv->wdog_ctrl == 0) { + dev_warn(dev->class_dev, "watchdog is disabled\n"); + return -EINVAL; + } + + /* "ping" the watchdog */ + for (i = 0; i < insn->n; i++) { + outl(spriv->wdog_ctrl | ADDI_WDOG_CTRL_SW_TRIG, + spriv->iobase + ADDI_WDOG_CTRL_REG); + } + + return insn->n; +} + +void addi_watchdog_reset(unsigned long iobase) +{ + outl(0x0, iobase + ADDI_WDOG_CTRL_REG); + outl(0x0, iobase + ADDI_WDOG_RELOAD_REG); +} +EXPORT_SYMBOL_GPL(addi_watchdog_reset); + +int addi_watchdog_init(struct comedi_subdevice *s, unsigned long iobase) +{ + struct addi_watchdog_private *spriv; + + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) + return -ENOMEM; + + spriv->iobase = iobase; + + s->type = COMEDI_SUBD_TIMER; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 1; + s->maxdata = 0xff; + s->insn_config = addi_watchdog_insn_config; + s->insn_read = addi_watchdog_insn_read; + s->insn_write = addi_watchdog_insn_write; + + return 0; +} +EXPORT_SYMBOL_GPL(addi_watchdog_init); + +static int __init addi_watchdog_module_init(void) +{ + return 0; +} +module_init(addi_watchdog_module_init); + +static void __exit addi_watchdog_module_exit(void) +{ +} +module_exit(addi_watchdog_module_exit); + +MODULE_DESCRIPTION("ADDI-DATA Watchdog subdevice"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/addi_watchdog.h b/drivers/staging/comedi/drivers/addi_watchdog.h new file mode 100644 index 00000000000..83b47befa4d --- /dev/null +++ b/drivers/staging/comedi/drivers/addi_watchdog.h @@ -0,0 +1,9 @@ +#ifndef _ADDI_WATCHDOG_H +#define _ADDI_WATCHDOG_H + +#include "../comedidev.h" + +void addi_watchdog_reset(unsigned long iobase); +int addi_watchdog_init(struct comedi_subdevice *, unsigned long iobase); + +#endif diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 4fc9e852021..921f6942dfc 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -1,447 +1,260 @@ /* - comedi/drivers/adl_pci6208.c - - Hardware driver for ADLink 6208 series cards: - card | voltage output | current output - -------------+-------------------+--------------- - PCI-6208V | 8 channels | - - PCI-6216V | 16 channels | - - PCI-6208A | 8 channels | 8 channels - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* -Driver: adl_pci6208 -Description: ADLink PCI-6208A -Devices: [ADLink] PCI-6208A (adl_pci6208) -Author: nsyeow <nsyeow@pd.jaring.my> -Updated: Fri, 30 Jan 2004 14:44:27 +0800 -Status: untested - -Configuration Options: - none - -References: - - ni_660x.c - - adl_pci9111.c copied the entire pci setup section - - adl_pci9118.c -*/ + * adl_pci6208.c + * Comedi driver for ADLink 6208 series cards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* - * 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. + * Driver: adl_pci6208 + * Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards + * Devices: (ADLink) PCI-6208 [adl_pci6208] + * (ADLink) PCI-6216 [adl_pci6216] + * Author: nsyeow <nsyeow@pd.jaring.my> + * Updated: Fri, 30 Jan 2004 14:44:27 +0800 + * Status: untested * - * Somewhere in the comment should be information about configuration - * options that are used with comedi_config. + * Configuration Options: not applicable, uses PCI auto config */ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/pci.h> + #include "../comedidev.h" -#include "comedi_pci.h" -#define PCI6208_DRIVER_NAME "adl_pci6208" +/* + * PCI-6208/6216-GL register map + */ +#define PCI6208_AO_CONTROL(x) (0x00 + (2 * (x))) +#define PCI6208_AO_STATUS 0x00 +#define PCI6208_AO_STATUS_DATA_SEND (1 << 0) +#define PCI6208_DIO 0x40 +#define PCI6208_DIO_DO_MASK (0x0f) +#define PCI6208_DIO_DO_SHIFT (0) +#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, +}; -/* Board descriptions */ struct pci6208_board { const char *name; - unsigned short dev_id; /* `lspci` will show you this */ int ao_chans; - /* int ao_bits; */ }; static const struct pci6208_board pci6208_boards[] = { - /*{ - .name = "pci6208v", - .dev_id = 0x6208, // not sure - .ao_chans = 8 - // , .ao_bits = 16 - }, - { - .name = "pci6216v", - .dev_id = 0x6208, // not sure - .ao_chans = 16 - // , .ao_bits = 16 - }, */ - { - .name = "pci6208a", - .dev_id = 0x6208, - .ao_chans = 8 - /* , .ao_bits = 16 */ - } + [BOARD_PCI6208] = { + .name = "adl_pci6208", + .ao_chans = 8, + }, + [BOARD_PCI6216] = { + .name = "adl_pci6216", + .ao_chans = 16, + }, }; -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -static DEFINE_PCI_DEVICE_TABLE(pci6208_pci_table) = { - /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ - /* { PCI_VENDOR_ID_ADLINK, 0x6208, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, */ - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci6208_pci_table); - -/* Will be initialized in pci6208_find device(). */ -#define thisboard ((const struct pci6208_board *)dev->board_ptr) - struct pci6208_private { - int data; - struct pci_dev *pci_dev; /* for a PCI device */ - unsigned int ao_readback[2]; /* Used for AO readback */ -}; - -#define devpriv ((struct pci6208_private *)dev->private) - -static int pci6208_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci6208_detach(struct comedi_device *dev); - -static struct comedi_driver driver_pci6208 = { - .driver_name = PCI6208_DRIVER_NAME, - .module = THIS_MODULE, - .attach = pci6208_attach, - .detach = pci6208_detach, + unsigned int ao_readback[PCI6208_MAX_AO_CHANNELS]; }; -static int __devinit driver_pci6208_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static int pci6208_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - return comedi_pci_auto_config(dev, driver_pci6208.driver_name); -} + unsigned int status; -static void __devexit driver_pci6208_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); + status = inw(dev->iobase + PCI6208_AO_STATUS); + if ((status & PCI6208_AO_STATUS_DATA_SEND) == 0) + return 0; + return -EBUSY; } -static struct pci_driver driver_pci6208_pci_driver = { - .id_table = pci6208_pci_table, - .probe = &driver_pci6208_pci_probe, - .remove = __devexit_p(&driver_pci6208_pci_remove) -}; - -static int __init driver_pci6208_init_module(void) +static int pci6208_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int retval; + struct pci6208_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int ret; + int i; - retval = comedi_driver_register(&driver_pci6208); - if (retval < 0) - return retval; + for (i = 0; i < insn->n; i++) { + val = data[i]; - driver_pci6208_pci_driver.name = (char *)driver_pci6208.driver_name; - return pci_register_driver(&driver_pci6208_pci_driver); -} + /* D/A transfer rate is 2.2us */ + ret = comedi_timeout(dev, s, insn, pci6208_ao_eoc, 0); + if (ret) + return ret; -static void __exit driver_pci6208_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci6208_pci_driver); - comedi_driver_unregister(&driver_pci6208); -} + /* the hardware expects two's complement values */ + outw(comedi_offset_munge(s, val), + dev->iobase + PCI6208_AO_CONTROL(chan)); + } + devpriv->ao_readback[chan] = val; -module_init(driver_pci6208_init_module); -module_exit(driver_pci6208_cleanup_module); - -static int pci6208_find_device(struct comedi_device *dev, int bus, int slot); -static int -pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr, - int dev_minor); - -/*read/write functions*/ -static int pci6208_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pci6208_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -/* static int pci6208_dio_insn_bits (struct comedi_device *dev, - * struct comedi_subdevice *s, */ -/* struct comedi_insn *insn,unsigned int *data); */ -/* static int pci6208_dio_insn_config(struct comedi_device *dev, - * struct comedi_subdevice *s, */ -/* struct comedi_insn *insn,unsigned int *data); */ + return insn->n; +} -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pci6208_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci6208_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct comedi_subdevice *s; - int retval; - unsigned long io_base; - - printk(KERN_INFO "comedi%d: pci6208: ", dev->minor); - - retval = alloc_private(dev, sizeof(struct pci6208_private)); - if (retval < 0) - return retval; - - retval = pci6208_find_device(dev, it->options[0], it->options[1]); - if (retval < 0) - return retval; - - retval = pci6208_pci_setup(devpriv->pci_dev, &io_base, dev->minor); - if (retval < 0) - return retval; - - dev->iobase = io_base; - dev->board_name = thisboard->name; + struct pci6208_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - s = dev->subdevices + 0; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; /* anything else to add here?? */ - s->n_chan = thisboard->ao_chans; - s->maxdata = 0xffff; /* 16-bit DAC */ - s->range_table = &range_bipolar10; /* this needs to be checked. */ - s->insn_write = pci6208_ao_winsn; - s->insn_read = pci6208_ao_rinsn; - - /* s=dev->subdevices+1; */ - /* digital i/o subdevice */ - /* 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 = pci6208_dio_insn_bits; */ - /* s->insn_config = pci6208_dio_insn_config; */ - - printk(KERN_INFO "attached\n"); - - return 1; + return insn->n; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pci6208_detach(struct comedi_device *dev) +static int pci6208_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - printk(KERN_INFO "comedi%d: pci6208: remove\n", dev->minor); - - if (devpriv && devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } + unsigned int val; - return 0; -} + val = inw(dev->iobase + PCI6208_DIO); + val = (val & PCI6208_DIO_DI_MASK) >> PCI6208_DIO_DI_SHIFT; -static int pci6208_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i = 0, Data_Read; - unsigned short chan = CR_CHAN(insn->chanspec); - unsigned long invert = 1 << (16 - 1); - unsigned long out_value; - /* 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++) { - out_value = data[i] ^ invert; - /* a typical programming sequence */ - do { - Data_Read = (inw(dev->iobase) & 1); - } while (Data_Read); - outw(out_value, dev->iobase + (0x02 * chan)); - devpriv->ao_readback[chan] = out_value; - } + data[1] = val; - /* return the number of samples read/written */ - return i; + return insn->n; } -/* AO subdevices should have a read insn as well as a write insn. - * Usually this means copying a value stored in devpriv. */ -static int pci6208_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pci6208_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int i; - int chan = CR_CHAN(insn->chanspec); + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + PCI6208_DIO); - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + data[1] = s->state; - return i; + return insn->n; } -/* 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 pci6208_dio_insn_bits(struct comedi_device *dev, - * struct comedi_subdevice *s, */ -/* struct comedi_insn *insn,unsigned int *data) */ -/* { */ -/* if(insn->n!=2)return -EINVAL; */ - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ -/* if(data[0]){ */ -/* s->state &= ~data[0]; */ -/* s->state |= data[0]&data[1]; */ - /* 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 2; */ -/* } */ - -/* static int pci6208_dio_insn_config(struct comedi_device *dev, - * struct comedi_subdevice *s, */ -/* struct comedi_insn *insn,unsigned int *data) */ -/* { */ -/* int chan=CR_CHAN(insn->chanspec); */ - - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ - -/* if(data[0]==COMEDI_OUTPUT){ */ -/* s->io_bits |= 1<<chan; */ -/* }else{ */ -/* s->io_bits &= ~(1<<chan); */ -/* } */ - /* outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); */ - -/* return 1; */ -/* } */ - -static int pci6208_find_device(struct comedi_device *dev, int bus, int slot) +static int pci6208_auto_attach(struct comedi_device *dev, + unsigned long context) { - struct pci_dev *pci_dev = NULL; - int i; - - for_each_pci_dev(pci_dev) { - if (pci_dev->vendor == PCI_VENDOR_ID_ADLINK) { - for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) { - if (pci6208_boards[i].dev_id == - pci_dev->device) { - /* - * was a particular bus/slot requested? - */ - if ((bus != 0) || (slot != 0)) { - /* - * are we on the - * wrong bus/slot? - */ - if (pci_dev->bus->number - != bus || - PCI_SLOT(pci_dev->devfn) - != slot) { - continue; - } - } - dev->board_ptr = pci6208_boards + i; - goto found; - } - } - } - } - - printk(KERN_ERR "comedi%d: no supported board found! " - "(req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return -EIO; + 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; + + if (context < ARRAY_SIZE(pci6208_boards)) + boardinfo = &pci6208_boards[context]; + if (!boardinfo) + return -ENODEV; + dev->board_ptr = boardinfo; + dev->board_name = boardinfo->name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; -found: - printk("comedi%d: found %s (b:s:f=%d:%d:%d) , irq=%d\n", - dev->minor, - pci6208_boards[i].name, - pci_dev->bus->number, - PCI_SLOT(pci_dev->devfn), - PCI_FUNC(pci_dev->devfn), pci_dev->irq); + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 2); - /* TODO: Warn about non-tested boards. */ - /* switch(board->device_id) */ - /* { */ - /* }; */ + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; - devpriv->pci_dev = pci_dev; + s = &dev->subdevices[0]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = boardinfo->ao_chans; + s->maxdata = 0xffff; + s->range_table = &range_bipolar10; + s->insn_write = pci6208_ao_insn_write; + s->insn_read = pci6208_ao_insn_read; + + s = &dev->subdevices[1]; + /* digital input subdevice */ + 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 = pci6208_di_insn_bits; + + s = &dev->subdevices[2]; + /* digital output subdevice */ + 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 = pci6208_do_insn_bits; + + /* + * Get the read back signals from the digital outputs + * and save it as the initial state for the subdevice. + */ + val = inw(dev->iobase + PCI6208_DIO); + val = (val & PCI6208_DIO_DO_MASK) >> PCI6208_DIO_DO_SHIFT; + s->state = val; return 0; } -static int -pci6208_pci_setup(struct pci_dev *pci_dev, unsigned long *io_base_ptr, - int dev_minor) -{ - unsigned long io_base, io_range, lcr_io_base, lcr_io_range; - - /* Enable PCI device and request regions */ - if (comedi_pci_enable(pci_dev, PCI6208_DRIVER_NAME) < 0) { - printk(KERN_ERR "comedi%d: Failed to enable PCI device " - "and request regions\n", - dev_minor); - return -EIO; - } - /* Read local configuration register - * base address [PCI_BASE_ADDRESS #1]. - */ - lcr_io_base = pci_resource_start(pci_dev, 1); - lcr_io_range = pci_resource_len(pci_dev, 1); - - printk(KERN_INFO "comedi%d: local config registers at address" - " 0x%4lx [0x%4lx]\n", - dev_minor, lcr_io_base, lcr_io_range); - - /* Read PCI6208 register base address [PCI_BASE_ADDRESS #2]. */ - io_base = pci_resource_start(pci_dev, 2); - io_range = pci_resource_end(pci_dev, 2) - io_base + 1; +static struct comedi_driver adl_pci6208_driver = { + .driver_name = "adl_pci6208", + .module = THIS_MODULE, + .auto_attach = pci6208_auto_attach, + .detach = comedi_pci_disable, +}; - printk("comedi%d: 6208 registers at address 0x%4lx [0x%4lx]\n", - dev_minor, io_base, io_range); +static int adl_pci6208_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &adl_pci6208_driver, + id->driver_data); +} - *io_base_ptr = io_base; - /* devpriv->io_range = io_range; */ - /* devpriv->is_valid=0; */ - /* devpriv->lcr_io_base=lcr_io_base; */ - /* devpriv->lcr_io_range=lcr_io_range; */ +static const struct pci_device_id adl_pci6208_pci_table[] = { + { PCI_VDEVICE(ADLINK, 0x6208), BOARD_PCI6208 }, + { PCI_VDEVICE(ADLINK, 0x6216), BOARD_PCI6216 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table); - return 0; -} +static struct pci_driver adl_pci6208_pci_driver = { + .name = "adl_pci6208", + .id_table = adl_pci6208_pci_table, + .probe = adl_pci6208_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adl_pci6208_driver, adl_pci6208_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for ADLink 6208 series cards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c deleted file mode 100644 index 72a7258b5b9..00000000000 --- a/drivers/staging/comedi/drivers/adl_pci7230.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - comedi/drivers/adl_pci7230.c - - Hardware comedi driver fot PCI7230 Adlink card - Copyright (C) 2010 David Fernandez <dfcastelao@gmail.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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: adl_pci7230 -Description: Driver for the Adlink PCI-7230 32 ch. isolated digital io board -Devices: [ADLink] PCI-7230 (adl_pci7230) -Author: David Fernandez <dfcastelao@gmail.com> -Status: experimental -Updated: Mon, 14 Apr 2008 15:08:14 +0100 - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. -*/ - -#include "../comedidev.h" -#include <linux/kernel.h> -#include "comedi_pci.h" - -#define PCI7230_DI 0x00 -#define PCI7230_DO 0x00 - -#define PCI_DEVICE_ID_PCI7230 0x7230 - -static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = { - { - PCI_VENDOR_ID_ADLINK, - PCI_DEVICE_ID_PCI7230, - PCI_ANY_ID, - PCI_ANY_ID, - 0, - 0, - 0 - }, - {0} -}; - -MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table); - -struct adl_pci7230_private { - int data; - struct pci_dev *pci_dev; -}; - -#define devpriv ((struct adl_pci7230_private *)dev->private) - -static int adl_pci7230_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adl_pci7230_detach(struct comedi_device *dev); -static struct comedi_driver driver_adl_pci7230 = { - .driver_name = "adl_pci7230", - .module = THIS_MODULE, - .attach = adl_pci7230_attach, - .detach = adl_pci7230_detach, -}; - -/* Digital IO */ - -static int adl_pci7230_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci7230_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci7230_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - struct comedi_subdevice *s; - int bus, slot; - - printk(KERN_INFO "comedi%d: adl_pci7230\n", dev->minor); - - dev->board_name = "pci7230"; - bus = it->options[0]; - slot = it->options[1]; - - if (alloc_private(dev, sizeof(struct adl_pci7230_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && - pcidev->device == PCI_DEVICE_ID_PCI7230) { - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) { - continue; - } - } - devpriv->pci_dev = pcidev; - break; - } - } - if (pcidev == NULL) { - printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return -EIO; - } - if (comedi_pci_enable(pcidev, "adl_pci7230") < 0) { - printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n", - dev->minor); - return -EIO; - } - dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase); - - s = dev->subdevices + 0; - /* Isolated do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = adl_pci7230_do_insn_bits; - - s = dev->subdevices + 1; - /* Isolated di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = adl_pci7230_di_insn_bits; - - printk(KERN_DEBUG "comedi: attached\n"); - - return 1; -} - -static int adl_pci7230_detach(struct comedi_device *dev) -{ - printk(KERN_DEBUG "comedi%d: pci7230: remove\n", dev->minor); - - if (devpriv && devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - - return 0; -} - -static int adl_pci7230_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO); - } - - return 2; -} - -static int adl_pci7230_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff; - - return 2; -} - -static int __devinit driver_adl_pci7230_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_adl_pci7230.driver_name); -} - -static void __devexit driver_adl_pci7230_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_adl_pci7230_pci_driver = { - .id_table = adl_pci7230_pci_table, - .probe = &driver_adl_pci7230_pci_probe, - .remove = __devexit_p(&driver_adl_pci7230_pci_remove) -}; - -static int __init driver_adl_pci7230_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_adl_pci7230); - if (retval < 0) - return retval; - - driver_adl_pci7230_pci_driver.name = - (char *)driver_adl_pci7230.driver_name; - return pci_register_driver(&driver_adl_pci7230_pci_driver); -} - -static void __exit driver_adl_pci7230_cleanup_module(void) -{ - pci_unregister_driver(&driver_adl_pci7230_pci_driver); - comedi_driver_unregister(&driver_adl_pci7230); -} - -module_init(driver_adl_pci7230_init_module); -module_exit(driver_adl_pci7230_cleanup_module); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c deleted file mode 100644 index f28fe6bec05..00000000000 --- a/drivers/staging/comedi/drivers/adl_pci7296.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - comedi/drivers/adl_pci7296.c - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: adl_pci7296 -Description: Driver for the Adlink PCI-7296 96 ch. digital io board -Devices: [ADLink] PCI-7296 (adl_pci7296) -Author: Jon Grierson <jd@renko.co.uk> -Updated: Mon, 14 Apr 2008 15:05:56 +0100 -Status: testing - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. -*/ - -#include "../comedidev.h" -#include <linux/kernel.h> - -#include "comedi_pci.h" -#include "8255.h" -/* #include "8253.h" */ - -#define PORT1A 0 -#define PORT2A 4 -#define PORT3A 8 -#define PORT4A 12 - -#define PCI_DEVICE_ID_PCI7296 0x7296 - -static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = { - { - PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table); - -struct adl_pci7296_private { - int data; - struct pci_dev *pci_dev; -}; - -#define devpriv ((struct adl_pci7296_private *)dev->private) - -static int adl_pci7296_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adl_pci7296_detach(struct comedi_device *dev); -static struct comedi_driver driver_adl_pci7296 = { - .driver_name = "adl_pci7296", - .module = THIS_MODULE, - .attach = adl_pci7296_attach, - .detach = adl_pci7296_detach, -}; - -static int adl_pci7296_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - struct comedi_subdevice *s; - int bus, slot; - int ret; - - printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor); - - dev->board_name = "pci7432"; - bus = it->options[0]; - slot = it->options[1]; - - if (alloc_private(dev, sizeof(struct adl_pci7296_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && - pcidev->device == PCI_DEVICE_ID_PCI7296) { - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus - || PCI_SLOT(pcidev->devfn) != slot) { - continue; - } - } - devpriv->pci_dev = pcidev; - if (comedi_pci_enable(pcidev, "adl_pci7296") < 0) { - printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n", - dev->minor); - return -EIO; - } - - dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_INFO "comedi: base addr %4lx\n", - dev->iobase); - - /* four 8255 digital io subdevices */ - s = dev->subdevices + 0; - subdev_8255_init(dev, s, NULL, - (unsigned long)(dev->iobase)); - - s = dev->subdevices + 1; - ret = subdev_8255_init(dev, s, NULL, - (unsigned long)(dev->iobase + - PORT2A)); - if (ret < 0) - return ret; - - s = dev->subdevices + 2; - ret = subdev_8255_init(dev, s, NULL, - (unsigned long)(dev->iobase + - PORT3A)); - if (ret < 0) - return ret; - - s = dev->subdevices + 3; - ret = subdev_8255_init(dev, s, NULL, - (unsigned long)(dev->iobase + - PORT4A)); - if (ret < 0) - return ret; - - printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", - dev->minor); - - return 1; - } - } - - printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return -EIO; -} - -static int adl_pci7296_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor); - - if (devpriv && devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - /* detach four 8255 digital io subdevices */ - if (dev->subdevices) { - subdev_8255_cleanup(dev, dev->subdevices + 0); - subdev_8255_cleanup(dev, dev->subdevices + 1); - subdev_8255_cleanup(dev, dev->subdevices + 2); - subdev_8255_cleanup(dev, dev->subdevices + 3); - - } - - return 0; -} - -static int __devinit driver_adl_pci7296_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_adl_pci7296.driver_name); -} - -static void __devexit driver_adl_pci7296_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_adl_pci7296_pci_driver = { - .id_table = adl_pci7296_pci_table, - .probe = &driver_adl_pci7296_pci_probe, - .remove = __devexit_p(&driver_adl_pci7296_pci_remove) -}; - -static int __init driver_adl_pci7296_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_adl_pci7296); - if (retval < 0) - return retval; - - driver_adl_pci7296_pci_driver.name = - (char *)driver_adl_pci7296.driver_name; - return pci_register_driver(&driver_adl_pci7296_pci_driver); -} - -static void __exit driver_adl_pci7296_cleanup_module(void) -{ - pci_unregister_driver(&driver_adl_pci7296_pci_driver); - comedi_driver_unregister(&driver_adl_pci7296); -} - -module_init(driver_adl_pci7296_init_module); -module_exit(driver_adl_pci7296_cleanup_module); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c deleted file mode 100644 index 262da7b29b2..00000000000 --- a/drivers/staging/comedi/drivers/adl_pci7432.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - comedi/drivers/adl_pci7432.c - - Hardware comedi driver fot PCI7432 Adlink card - Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: adl_pci7432 -Description: Driver for the Adlink PCI-7432 64 ch. isolated digital io board -Devices: [ADLink] PCI-7432 (adl_pci7432) -Author: Michel Lachaine <mike@mikelachaine.ca> -Status: experimental -Updated: Mon, 14 Apr 2008 15:08:14 +0100 - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. -*/ - -#include "../comedidev.h" -#include <linux/kernel.h> -#include "comedi_pci.h" - -#define PCI7432_DI 0x00 -#define PCI7432_DO 0x00 - -#define PCI_DEVICE_ID_PCI7432 0x7432 - -static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = { - { - PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table); - -struct adl_pci7432_private { - int data; - struct pci_dev *pci_dev; -}; - -#define devpriv ((struct adl_pci7432_private *)dev->private) - -static int adl_pci7432_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adl_pci7432_detach(struct comedi_device *dev); -static struct comedi_driver driver_adl_pci7432 = { - .driver_name = "adl_pci7432", - .module = THIS_MODULE, - .attach = adl_pci7432_attach, - .detach = adl_pci7432_detach, -}; - -/* Digital IO */ - -static int adl_pci7432_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci7432_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -/* */ - -static int adl_pci7432_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - struct comedi_subdevice *s; - int bus, slot; - - printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor); - - dev->board_name = "pci7432"; - bus = it->options[0]; - slot = it->options[1]; - - if (alloc_private(dev, sizeof(struct adl_pci7432_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && - pcidev->device == PCI_DEVICE_ID_PCI7432) { - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus - || PCI_SLOT(pcidev->devfn) != slot) { - continue; - } - } - devpriv->pci_dev = pcidev; - if (comedi_pci_enable(pcidev, "adl_pci7432") < 0) { - printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n", - dev->minor); - return -EIO; - } - dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_INFO "comedi: base addr %4lx\n", - dev->iobase); - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = - SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 32; - s->maxdata = 1; - s->len_chanlist = 32; - s->io_bits = 0x00000000; - s->range_table = &range_digital; - s->insn_bits = adl_pci7432_di_insn_bits; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = - SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 32; - s->maxdata = 1; - s->len_chanlist = 32; - s->io_bits = 0xffffffff; - s->range_table = &range_digital; - s->insn_bits = adl_pci7432_do_insn_bits; - - printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", - dev->minor); - return 1; - } - } - - printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return -EIO; -} - -static int adl_pci7432_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pci7432: remove\n", dev->minor); - - if (devpriv && devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - - return 0; -} - -static int adl_pci7432_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n"); - printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); - - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state, - dev->iobase + PCI7432_DO); - outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO); - } - return 2; -} - -static int adl_pci7432_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n"); - printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); - - if (insn->n != 2) - return -EINVAL; - - data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff; - printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]); - - return 2; -} - -static int __devinit driver_adl_pci7432_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_adl_pci7432.driver_name); -} - -static void __devexit driver_adl_pci7432_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_adl_pci7432_pci_driver = { - .id_table = adl_pci7432_pci_table, - .probe = &driver_adl_pci7432_pci_probe, - .remove = __devexit_p(&driver_adl_pci7432_pci_remove) -}; - -static int __init driver_adl_pci7432_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_adl_pci7432); - if (retval < 0) - return retval; - - driver_adl_pci7432_pci_driver.name = - (char *)driver_adl_pci7432.driver_name; - return pci_register_driver(&driver_adl_pci7432_pci_driver); -} - -static void __exit driver_adl_pci7432_cleanup_module(void) -{ - pci_unregister_driver(&driver_adl_pci7432_pci_driver); - comedi_driver_unregister(&driver_adl_pci7432); -} - -module_init(driver_adl_pci7432_init_module); -module_exit(driver_adl_pci7432_cleanup_module); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c new file mode 100644 index 00000000000..5e3cc77a8a0 --- /dev/null +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -0,0 +1,280 @@ +/* + * COMEDI driver for the ADLINK PCI-723x/743x series boards. + * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on the adl_pci7230 driver written by: + * David Fernandez <dfcastelao@gmail.com> + * and the adl_pci7432 driver written by: + * Michel Lachaine <mike@mikelachaine.ca> + * + * 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: adl_pci7x3x +Description: 32/64-Channel Isolated Digital I/O Boards +Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output + (ADLink) PCI-7233 [adl_pci7233] - 32 input + (ADLink) PCI-7234 [adl_pci7234] - 32 output + (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output + (ADLink) PCI-7433 [adl_pci7433] - 64 input + (ADLink) PCI-7434 [adl_pci7434] - 64 output +Author: H Hartley Sweeten <hsweeten@visionengravers.com> +Updated: Thu, 02 Aug 2012 14:27:46 -0700 +Status: untested + +The PCI-7230, PCI-7432 and PCI-7433 boards also support external +interrupt signals on digital input channels 0 and 1. The PCI-7233 +has dual-interrupt sources for change-of-state (COS) on any 16 +digital input channels of LSB and for COS on any 16 digital input +lines of MSB. Interrupts are not currently supported by this +driver. + +Configuration Options: not applicable, uses comedi PCI auto config +*/ + +#include <linux/module.h> +#include <linux/pci.h> + +#include "../comedidev.h" + +/* + * Register I/O map (32-bit access only) + */ +#define PCI7X3X_DIO_REG 0x00 +#define PCI743X_DIO_REG 0x04 + +enum apci1516_boardid { + BOARD_PCI7230, + BOARD_PCI7233, + BOARD_PCI7234, + BOARD_PCI7432, + BOARD_PCI7433, + BOARD_PCI7434, +}; + +struct adl_pci7x3x_boardinfo { + const char *name; + int nsubdevs; + int di_nchan; + int do_nchan; +}; + +static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = { + [BOARD_PCI7230] = { + .name = "adl_pci7230", + .nsubdevs = 2, + .di_nchan = 16, + .do_nchan = 16, + }, + [BOARD_PCI7233] = { + .name = "adl_pci7233", + .nsubdevs = 1, + .di_nchan = 32, + }, + [BOARD_PCI7234] = { + .name = "adl_pci7234", + .nsubdevs = 1, + .do_nchan = 32, + }, + [BOARD_PCI7432] = { + .name = "adl_pci7432", + .nsubdevs = 2, + .di_nchan = 32, + .do_nchan = 32, + }, + [BOARD_PCI7433] = { + .name = "adl_pci7433", + .nsubdevs = 2, + .di_nchan = 64, + }, + [BOARD_PCI7434] = { + .name = "adl_pci7434", + .nsubdevs = 2, + .do_nchan = 64, + } +}; + +static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned long reg = (unsigned long)s->private; + + if (comedi_dio_update_state(s, data)) + outl(s->state, dev->iobase + reg); + + data[1] = s->state; + + return insn->n; +} + +static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned long reg = (unsigned long)s->private; + + data[1] = inl(dev->iobase + reg); + + return insn->n; +} + +static int adl_pci7x3x_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct adl_pci7x3x_boardinfo *board = NULL; + struct comedi_subdevice *s; + int subdev; + int nchan; + int ret; + + if (context < ARRAY_SIZE(adl_pci7x3x_boards)) + board = &adl_pci7x3x_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 2); + + /* + * One or two subdevices are setup by this driver depending on + * the number of digital inputs and/or outputs provided by the + * board. Each subdevice has a maximum of 32 channels. + * + * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output + * PCI-7233 - 1 subdevice: 0 - 32 input + * PCI-7234 - 1 subdevice: 0 - 32 output + * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output + * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input + * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output + */ + ret = comedi_alloc_subdevices(dev, board->nsubdevs); + if (ret) + return ret; + + subdev = 0; + + if (board->di_nchan) { + nchan = min(board->di_nchan, 32); + + s = &dev->subdevices[subdev]; + /* Isolated digital inputs 0 to 15/31 */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = nchan; + s->maxdata = 1; + s->insn_bits = adl_pci7x3x_di_insn_bits; + s->range_table = &range_digital; + + s->private = (void *)PCI7X3X_DIO_REG; + + subdev++; + + nchan = board->di_nchan - nchan; + if (nchan) { + s = &dev->subdevices[subdev]; + /* Isolated digital inputs 32 to 63 */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = nchan; + s->maxdata = 1; + s->insn_bits = adl_pci7x3x_di_insn_bits; + s->range_table = &range_digital; + + s->private = (void *)PCI743X_DIO_REG; + + subdev++; + } + } + + if (board->do_nchan) { + nchan = min(board->do_nchan, 32); + + s = &dev->subdevices[subdev]; + /* Isolated digital outputs 0 to 15/31 */ + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = nchan; + s->maxdata = 1; + s->insn_bits = adl_pci7x3x_do_insn_bits; + s->range_table = &range_digital; + + s->private = (void *)PCI7X3X_DIO_REG; + + subdev++; + + nchan = board->do_nchan - nchan; + if (nchan) { + s = &dev->subdevices[subdev]; + /* Isolated digital outputs 32 to 63 */ + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = nchan; + s->maxdata = 1; + s->insn_bits = adl_pci7x3x_do_insn_bits; + s->range_table = &range_digital; + + s->private = (void *)PCI743X_DIO_REG; + + subdev++; + } + } + + return 0; +} + +static struct comedi_driver adl_pci7x3x_driver = { + .driver_name = "adl_pci7x3x", + .module = THIS_MODULE, + .auto_attach = adl_pci7x3x_auto_attach, + .detach = comedi_pci_disable, +}; + +static int adl_pci7x3x_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &adl_pci7x3x_driver, + id->driver_data); +} + +static const struct pci_device_id adl_pci7x3x_pci_table[] = { + { PCI_VDEVICE(ADLINK, 0x7230), BOARD_PCI7230 }, + { PCI_VDEVICE(ADLINK, 0x7233), BOARD_PCI7233 }, + { PCI_VDEVICE(ADLINK, 0x7234), BOARD_PCI7234 }, + { PCI_VDEVICE(ADLINK, 0x7432), BOARD_PCI7432 }, + { PCI_VDEVICE(ADLINK, 0x7433), BOARD_PCI7433 }, + { PCI_VDEVICE(ADLINK, 0x7434), BOARD_PCI7434 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table); + +static struct pci_driver adl_pci7x3x_pci_driver = { + .name = "adl_pci7x3x", + .id_table = adl_pci7x3x_pci_table, + .probe = adl_pci7x3x_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver); + +MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index 767a594935c..300df55a280 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -1,430 +1,163 @@ /* - comedi/drivers/adl_pci8164.c - - Hardware comedi driver fot PCI-8164 Adlink card - Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: adl_pci8164 -Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board -Devices: [ADLink] PCI-8164 (adl_pci8164) -Author: Michel Lachaine <mike@mikelachaine.ca> -Status: experimental -Updated: Mon, 14 Apr 2008 15:10:32 +0100 - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. -*/ - -#include "../comedidev.h" -#include <linux/kernel.h> -#include <linux/delay.h> -#include "comedi_fc.h" -#include "comedi_pci.h" -#include "8253.h" - -#define PCI8164_AXIS_X 0x00 -#define PCI8164_AXIS_Y 0x08 -#define PCI8164_AXIS_Z 0x10 -#define PCI8164_AXIS_U 0x18 - -#define PCI8164_MSTS 0x00 -#define PCI8164_SSTS 0x02 -#define PCI8164_BUF0 0x04 -#define PCI8164_BUF1 0x06 - -#define PCI8164_CMD 0x00 -#define PCI8164_OTP 0x02 - -#define PCI_DEVICE_ID_PCI8164 0x8164 - -static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = { - { - PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table); - -struct adl_pci8164_private { - int data; - struct pci_dev *pci_dev; -}; - -#define devpriv ((struct adl_pci8164_private *)dev->private) - -static int adl_pci8164_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adl_pci8164_detach(struct comedi_device *dev); -static struct comedi_driver driver_adl_pci8164 = { - .driver_name = "adl_pci8164", - .module = THIS_MODULE, - .attach = adl_pci8164_attach, - .detach = adl_pci8164_detach, -}; - -static int adl_pci8164_insn_read_msts(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_read_ssts(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_read_buf0(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_read_buf1(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_write_cmd(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_write_otp(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_write_buf0(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_insn_write_buf1(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static int adl_pci8164_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - struct comedi_subdevice *s; - int bus, slot; - - printk(KERN_INFO "comedi: attempt to attach...\n"); - printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor); - - dev->board_name = "pci8164"; - bus = it->options[0]; - slot = it->options[1]; - - if (alloc_private(dev, sizeof(struct adl_pci8164_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_ADLINK && - pcidev->device == PCI_DEVICE_ID_PCI8164) { - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus - || PCI_SLOT(pcidev->devfn) != slot) - continue; - } - devpriv->pci_dev = pcidev; - if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) { - printk(KERN_ERR "comedi%d: Failed to enable " - "PCI device and request regions\n", dev->minor); - return -EIO; - } - dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_DEBUG "comedi: base addr %4lx\n", - dev->iobase); - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_PROC; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - /* s->range_table = &range_axis; */ - s->insn_read = adl_pci8164_insn_read_msts; - s->insn_write = adl_pci8164_insn_write_cmd; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_PROC; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - /* s->range_table = &range_axis; */ - s->insn_read = adl_pci8164_insn_read_ssts; - s->insn_write = adl_pci8164_insn_write_otp; - - s = dev->subdevices + 2; - s->type = COMEDI_SUBD_PROC; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - /* s->range_table = &range_axis; */ - s->insn_read = adl_pci8164_insn_read_buf0; - s->insn_write = adl_pci8164_insn_write_buf0; - - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_PROC; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 4; - s->maxdata = 0xffff; - s->len_chanlist = 4; - /* s->range_table = &range_axis; */ - s->insn_read = adl_pci8164_insn_read_buf1; - s->insn_write = adl_pci8164_insn_write_buf1; - - printk(KERN_INFO "comedi: attached\n"); - - return 1; - } - } - - printk(KERN_ERR "comedi%d: no supported board found!" - "(req. bus/slot : %d/%d)\n", dev->minor, bus, slot); - return -EIO; -} - -static int adl_pci8164_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pci8164: remove\n", dev->minor); - - if (devpriv && devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - - return 0; -} + * comedi/drivers/adl_pci8164.c + * + * Hardware comedi driver for PCI-8164 Adlink card + * Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca> + * + * 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. + */ /* - all the read commands are the same except for the addition a constant - * const to the data for inw() + * Driver: adl_pci8164 + * Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board + * Devices: (ADLink) PCI-8164 [adl_pci8164] + * Author: Michel Lachaine <mike@mikelachaine.ca> + * Status: experimental + * Updated: Mon, 14 Apr 2008 15:10:32 +0100 + * + * Configuration Options: not applicable, uses PCI auto config */ -static void adl_pci8164_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data, - char *action, unsigned short offset) -{ - int axis, axis_reg; - char *axisname; - - axis = CR_CHAN(insn->chanspec); - - switch (axis) { - case 0: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - break; - case 1: - axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; - break; - case 2: - axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; - break; - case 3: - axis_reg = PCI8164_AXIS_U; - axisname = "U"; - break; - default: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - } - data[0] = inw(dev->iobase + axis_reg + offset); - printk(KERN_DEBUG "comedi: pci8164 %s read -> " - "%04X:%04X on axis %s\n", - action, data[0], data[1], axisname); -} - -static int adl_pci8164_insn_read_msts(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - adl_pci8164_insn_read(dev, s, insn, data, "MSTS", PCI8164_MSTS); - return 2; -} - -static int adl_pci8164_insn_read_ssts(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - adl_pci8164_insn_read(dev, s, insn, data, "SSTS", PCI8164_SSTS); - return 2; -} +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> -static int adl_pci8164_insn_read_buf0(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - adl_pci8164_insn_read(dev, s, insn, data, "BUF0", PCI8164_BUF0); - return 2; -} +#include "../comedidev.h" -static int adl_pci8164_insn_read_buf1(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - adl_pci8164_insn_read(dev, s, insn, data, "BUF1", PCI8164_BUF1); - return 2; -} +#define PCI8164_AXIS(x) ((x) * 0x08) +#define PCI8164_CMD_MSTS_REG 0x00 +#define PCI8164_OTP_SSTS_REG 0x02 +#define PCI8164_BUF0_REG 0x04 +#define PCI8164_BUF1_REG 0x06 -/* - all the write commands are the same except for the addition a constant - * const to the data for outw() - */ -static void adl_pci8164_insn_out(struct comedi_device *dev, +static int adl_pci8164_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data, - char *action, unsigned short offset) + unsigned int *data) { - unsigned int axis, axis_reg; + unsigned long offset = (unsigned long)s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - char *axisname; + for (i = 0; i < insn->n; i++) + data[i] = inw(dev->iobase + PCI8164_AXIS(chan) + offset); - axis = CR_CHAN(insn->chanspec); - - switch (axis) { - case 0: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - break; - case 1: - axis_reg = PCI8164_AXIS_Y; - axisname = "Y"; - break; - case 2: - axis_reg = PCI8164_AXIS_Z; - axisname = "Z"; - break; - case 3: - axis_reg = PCI8164_AXIS_U; - axisname = "U"; - break; - default: - axis_reg = PCI8164_AXIS_X; - axisname = "X"; - } - - outw(data[0], dev->iobase + axis_reg + offset); - - printk(KERN_DEBUG "comedi: pci8164 %s write -> " - "%04X:%04X on axis %s\n", - action, data[0], data[1], axisname); - -} - -static int adl_pci8164_insn_write_cmd(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - adl_pci8164_insn_out(dev, s, insn, data, "CMD", PCI8164_CMD); - return 2; + return insn->n; } -static int adl_pci8164_insn_write_otp(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int adl_pci8164_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - adl_pci8164_insn_out(dev, s, insn, data, "OTP", PCI8164_OTP); - return 2; -} + unsigned long offset = (unsigned long)s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; -static int adl_pci8164_insn_write_buf0(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - adl_pci8164_insn_out(dev, s, insn, data, "BUF0", PCI8164_BUF0); - return 2; -} + for (i = 0; i < insn->n; i++) + outw(data[i], dev->iobase + PCI8164_AXIS(chan) + offset); -static int adl_pci8164_insn_write_buf1(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - adl_pci8164_insn_out(dev, s, insn, data, "BUF1", PCI8164_BUF1); - return 2; + return insn->n; } -static int __devinit driver_adl_pci8164_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static int adl_pci8164_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - return comedi_pci_auto_config(dev, driver_adl_pci8164.driver_name); -} + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + int ret; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 2); + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* read MSTS register / write CMD register for each axis (channel) */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_PROC; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + s->insn_read = adl_pci8164_insn_read; + s->insn_write = adl_pci8164_insn_write; + s->private = (void *)PCI8164_CMD_MSTS_REG; + + /* read SSTS register / write OTP register for each axis (channel) */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_PROC; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + s->insn_read = adl_pci8164_insn_read; + s->insn_write = adl_pci8164_insn_write; + s->private = (void *)PCI8164_OTP_SSTS_REG; + + /* read/write BUF0 register for each axis (channel) */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_PROC; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + s->insn_read = adl_pci8164_insn_read; + s->insn_write = adl_pci8164_insn_write; + s->private = (void *)PCI8164_BUF0_REG; + + /* read/write BUF1 register for each axis (channel) */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_PROC; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + s->insn_read = adl_pci8164_insn_read; + s->insn_write = adl_pci8164_insn_write; + s->private = (void *)PCI8164_BUF1_REG; -static void __devexit driver_adl_pci8164_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); + return 0; } -static struct pci_driver driver_adl_pci8164_pci_driver = { - .id_table = adl_pci8164_pci_table, - .probe = &driver_adl_pci8164_pci_probe, - .remove = __devexit_p(&driver_adl_pci8164_pci_remove) +static struct comedi_driver adl_pci8164_driver = { + .driver_name = "adl_pci8164", + .module = THIS_MODULE, + .auto_attach = adl_pci8164_auto_attach, + .detach = comedi_pci_disable, }; -static int __init driver_adl_pci8164_init_module(void) +static int adl_pci8164_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_adl_pci8164); - if (retval < 0) - return retval; - - driver_adl_pci8164_pci_driver.name = - (char *)driver_adl_pci8164.driver_name; - return pci_register_driver(&driver_adl_pci8164_pci_driver); + return comedi_pci_auto_config(dev, &adl_pci8164_driver, + id->driver_data); } -static void __exit driver_adl_pci8164_cleanup_module(void) -{ - pci_unregister_driver(&driver_adl_pci8164_pci_driver); - comedi_driver_unregister(&driver_adl_pci8164); -} +static const struct pci_device_id adl_pci8164_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x8164) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table); -module_init(driver_adl_pci8164_init_module); -module_exit(driver_adl_pci8164_cleanup_module); +static struct pci_driver adl_pci8164_pci_driver = { + .name = "adl_pci8164", + .id_table = adl_pci8164_pci_table, + .probe = adl_pci8164_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index fc48bae42ab..584fd57ecb7 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -17,10 +17,6 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -47,14 +43,7 @@ Supports: The scanned channels must be consecutive and start from 0. They must all have the same range and aref. -Configuration options: - - [0] - PCI bus number (optional) - [1] - PCI slot number (optional) - -If bus/slot is not specified, the first available PCI -device will be used. - +Configuration options: not applicable, uses PCI auto config */ /* @@ -75,378 +64,92 @@ TODO: */ -#include "../comedidev.h" - +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include "../comedidev.h" + #include "8253.h" -#include "comedi_pci.h" +#include "plx9052.h" #include "comedi_fc.h" #define PCI9111_DRIVER_NAME "adl_pci9111" #define PCI9111_HR_DEVICE_ID 0x9111 -/* TODO: Add other pci9111 board id */ - -#define PCI9111_IO_RANGE 0x0100 - #define PCI9111_FIFO_HALF_SIZE 512 -#define PCI9111_AI_CHANNEL_NBR 16 - -#define PCI9111_AI_RESOLUTION 12 -#define PCI9111_AI_RESOLUTION_MASK 0x0FFF -#define PCI9111_AI_RESOLUTION_2_CMP_BIT 0x0800 - -#define PCI9111_HR_AI_RESOLUTION 16 -#define PCI9111_HR_AI_RESOLUTION_MASK 0xFFFF -#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT 0x8000 - #define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000 -#define PCI9111_AO_CHANNEL_NBR 1 -#define PCI9111_AO_RESOLUTION 12 -#define PCI9111_AO_RESOLUTION_MASK 0x0FFF -#define PCI9111_DI_CHANNEL_NBR 16 -#define PCI9111_DO_CHANNEL_NBR 16 -#define PCI9111_DO_MASK 0xFFFF #define PCI9111_RANGE_SETTING_DELAY 10 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2 -#define PCI9111_AI_INSTANT_READ_TIMEOUT 100 - -#define PCI9111_8254_CLOCK_PERIOD_NS 500 - -#define PCI9111_8254_COUNTER_0 0x00 -#define PCI9111_8254_COUNTER_1 0x40 -#define PCI9111_8254_COUNTER_2 0x80 -#define PCI9111_8254_COUNTER_LATCH 0x00 -#define PCI9111_8254_READ_LOAD_LSB_ONLY 0x10 -#define PCI9111_8254_READ_LOAD_MSB_ONLY 0x20 -#define PCI9111_8254_READ_LOAD_LSB_MSB 0x30 -#define PCI9111_8254_MODE_0 0x00 -#define PCI9111_8254_MODE_1 0x02 -#define PCI9111_8254_MODE_2 0x04 -#define PCI9111_8254_MODE_3 0x06 -#define PCI9111_8254_MODE_4 0x08 -#define PCI9111_8254_MODE_5 0x0A -#define PCI9111_8254_BINARY_COUNTER 0x00 -#define PCI9111_8254_BCD_COUNTER 0x01 - -/* IO address map */ - -#define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 /* AD Data stored - in FIFO */ -#define PCI9111_REGISTER_DA_OUTPUT 0x00 -#define PCI9111_REGISTER_DIGITAL_IO 0x02 -#define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04 -#define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 /* Channel - selection */ -#define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06 -#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08 -#define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08 -#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A -#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A -#define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E -#define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C -#define PCI9111_REGISTER_8254_COUNTER_0 0x40 -#define PCI9111_REGISTER_8254_COUNTER_1 0x42 -#define PCI9111_REGISTER_8254_COUNTER_2 0X44 -#define PCI9111_REGISTER_8254_CONTROL 0x46 -#define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48 - -#define PCI9111_TRIGGER_MASK 0x0F -#define PCI9111_PTRG_OFF (0 << 3) -#define PCI9111_PTRG_ON (1 << 3) -#define PCI9111_EITS_EXTERNAL (1 << 2) -#define PCI9111_EITS_INTERNAL (0 << 2) -#define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1) -#define PCI9111_TPST_TIMER_PACER (1 << 1) -#define PCI9111_ASCAN_ON (1 << 0) -#define PCI9111_ASCAN_OFF (0 << 0) - -#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0) -#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0) -#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1) -#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1) -#define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2) -#define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2) - -#define PCI9111_CHANNEL_MASK 0x0F - -#define PCI9111_RANGE_MASK 0x07 -#define PCI9111_FIFO_EMPTY_MASK 0x10 -#define PCI9111_FIFO_HALF_FULL_MASK 0x20 -#define PCI9111_FIFO_FULL_MASK 0x40 -#define PCI9111_AD_BUSY_MASK 0x80 - -#define PCI9111_IO_BASE (dev->iobase) /* - * Define inlined function + * IO address map and bit defines */ - -#define pci9111_trigger_and_autoscan_get() \ - (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F) - -#define pci9111_trigger_and_autoscan_set(flags) \ - outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL) - -#define pci9111_interrupt_and_fifo_get() \ - ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) \ - >> 4) & 0x03) - -#define pci9111_interrupt_and_fifo_set(flags) \ - outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL) - -#define pci9111_interrupt_clear() \ - outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR) - -#define pci9111_software_trigger() \ - outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER) - -#define pci9111_fifo_reset() do { \ - outb(PCI9111_FFEN_SET_FIFO_ENABLE, \ - PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ - outb(PCI9111_FFEN_SET_FIFO_DISABLE, \ - PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ - outb(PCI9111_FFEN_SET_FIFO_ENABLE, \ - PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ - } while (0) - -#define pci9111_is_fifo_full() \ - ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ - PCI9111_FIFO_FULL_MASK) == 0) - -#define pci9111_is_fifo_half_full() \ - ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ - PCI9111_FIFO_HALF_FULL_MASK) == 0) - -#define pci9111_is_fifo_empty() \ - ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ - PCI9111_FIFO_EMPTY_MASK) == 0) - -#define pci9111_ai_channel_set(channel) \ - outb((channel)&PCI9111_CHANNEL_MASK, \ - PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL) - -#define pci9111_ai_channel_get() \ - (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK) \ - &PCI9111_CHANNEL_MASK) - -#define pci9111_ai_range_set(range) \ - outb((range)&PCI9111_RANGE_MASK, \ - PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE) - -#define pci9111_ai_range_get() \ - (inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK) \ - &PCI9111_RANGE_MASK) - -#define pci9111_ai_get_data() \ - (((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4) \ - &PCI9111_AI_RESOLUTION_MASK) \ - ^ PCI9111_AI_RESOLUTION_2_CMP_BIT) - -#define pci9111_hr_ai_get_data() \ - ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) \ - &PCI9111_HR_AI_RESOLUTION_MASK) \ - ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT) - -#define pci9111_ao_set_data(data) \ - outw(data&PCI9111_AO_RESOLUTION_MASK, \ - PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT) - -#define pci9111_di_get_bits() \ - inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO) - -#define pci9111_do_set_bits(bits) \ - outw(bits, PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO) - -#define pci9111_8254_control_set(flags) \ - outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL) - -#define pci9111_8254_counter_0_set(data) \ - do { \ - outb(data & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \ - outb((data >> 8) & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \ - } while (0) - -#define pci9111_8254_counter_1_set(data) \ - do { \ - outb(data & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \ - outb((data >> 8) & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \ - } while (0) - -#define pci9111_8254_counter_2_set(data) \ - do { \ - outb(data & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \ - outb((data >> 8) & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \ - } while (0) - -/* Function prototypes */ - -static int pci9111_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci9111_detach(struct comedi_device *dev); -static void pci9111_ai_munge(struct comedi_device *dev, - struct comedi_subdevice *s, void *data, - unsigned int num_bytes, - unsigned int start_chan_index); - -static const struct comedi_lrange pci9111_hr_ai_range = { - 5, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625) - } -}; - -static DEFINE_PCI_DEVICE_TABLE(pci9111_pci_table) = { - { PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, - 0, 0, 0 }, - /* { PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, - * 0, 0, 0 }, */ - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci9111_pci_table); - -/* */ -/* Board specification structure */ -/* */ - -struct pci9111_board { - const char *name; /* driver name */ - int device_id; - int ai_channel_nbr; /* num of A/D chans */ - int ao_channel_nbr; /* num of D/A chans */ - int ai_resolution; /* resolution of A/D */ - int ai_resolution_mask; - int ao_resolution; /* resolution of D/A */ - int ao_resolution_mask; - const struct comedi_lrange *ai_range_list; /* rangelist for A/D */ - const struct comedi_lrange *ao_range_list; /* rangelist for D/A */ - unsigned int ai_acquisition_period_min_ns; -}; - -static const struct pci9111_board pci9111_boards[] = { - { - .name = "pci9111_hr", - .device_id = PCI9111_HR_DEVICE_ID, - .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR, - .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR, - .ai_resolution = PCI9111_HR_AI_RESOLUTION, - .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK, - .ao_resolution = PCI9111_AO_RESOLUTION, - .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK, - .ai_range_list = &pci9111_hr_ai_range, - .ao_range_list = &range_bipolar10, - .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS} -}; - -#define pci9111_board_nbr \ - (sizeof(pci9111_boards)/sizeof(struct pci9111_board)) - -static struct comedi_driver pci9111_driver = { - .driver_name = PCI9111_DRIVER_NAME, - .module = THIS_MODULE, - .attach = pci9111_attach, - .detach = pci9111_detach, -}; - -static int __devinit pci9111_driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, pci9111_driver.driver_name); -} - -static void __devexit pci9111_driver_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver pci9111_driver_pci_driver = { - .id_table = pci9111_pci_table, - .probe = &pci9111_driver_pci_probe, - .remove = __devexit_p(&pci9111_driver_pci_remove) +#define PCI9111_AI_FIFO_REG 0x00 +#define PCI9111_AO_REG 0x00 +#define PCI9111_DIO_REG 0x02 +#define PCI9111_EDIO_REG 0x04 +#define PCI9111_AI_CHANNEL_REG 0x06 +#define PCI9111_AI_RANGE_STAT_REG 0x08 +#define PCI9111_AI_STAT_AD_BUSY (1 << 7) +#define PCI9111_AI_STAT_FF_FF (1 << 6) +#define PCI9111_AI_STAT_FF_HF (1 << 5) +#define PCI9111_AI_STAT_FF_EF (1 << 4) +#define PCI9111_AI_RANGE_MASK (7 << 0) +#define PCI9111_AI_TRIG_CTRL_REG 0x0a +#define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5) +#define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4) +#define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3) +#define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2) +#define PCI9111_AI_TRIG_CTRL_TPST (1 << 1) +#define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0) +#define PCI9111_INT_CTRL_REG 0x0c +#define PCI9111_INT_CTRL_ISC2 (1 << 3) +#define PCI9111_INT_CTRL_FFEN (1 << 2) +#define PCI9111_INT_CTRL_ISC1 (1 << 1) +#define PCI9111_INT_CTRL_ISC0 (1 << 0) +#define PCI9111_SOFT_TRIG_REG 0x0e +#define PCI9111_8254_BASE_REG 0x40 +#define PCI9111_INT_CLR_REG 0x48 + +/* PLX 9052 Local Interrupt 1 enabled and active */ +#define PCI9111_LI1_ACTIVE (PLX9052_INTCSR_LI1ENAB | \ + PLX9052_INTCSR_LI1STAT) + +/* PLX 9052 Local Interrupt 2 enabled and active */ +#define PCI9111_LI2_ACTIVE (PLX9052_INTCSR_LI2ENAB | \ + PLX9052_INTCSR_LI2STAT) + +static const struct comedi_lrange pci9111_ai_range = { + 5, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static int __init pci9111_driver_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&pci9111_driver); - if (retval < 0) - return retval; - - pci9111_driver_pci_driver.name = (char *)pci9111_driver.driver_name; - return pci_register_driver(&pci9111_driver_pci_driver); -} - -static void __exit pci9111_driver_cleanup_module(void) -{ - pci_unregister_driver(&pci9111_driver_pci_driver); - comedi_driver_unregister(&pci9111_driver); -} - -module_init(pci9111_driver_init_module); -module_exit(pci9111_driver_cleanup_module); - -/* Private data structure */ - struct pci9111_private_data { - struct pci_dev *pci_device; - unsigned long io_range; /* PCI6503 io range */ - - unsigned long lcr_io_base; /* Local configuration register base - * address */ - unsigned long lcr_io_range; + unsigned long lcr_io_base; int stop_counter; - int stop_is_none; unsigned int scan_delay; - unsigned int chanlist_len; unsigned int chunk_counter; unsigned int chunk_num_samples; - int ao_readback; /* Last written analog output data */ - - unsigned int timer_divisor_1; /* Divisor values for the 8254 timer - * pacer */ - unsigned int timer_divisor_2; + int ao_readback; - int is_valid; /* Is device valid */ + unsigned int div1; + unsigned int div2; - short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; + unsigned short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; }; -#define dev_private ((struct pci9111_private_data *)dev->private) - -/* ------------------------------------------------------------------ */ -/* PLX9050 SECTION */ -/* ------------------------------------------------------------------ */ - -#define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c - -#define PLX9050_LINTI1_ENABLE (1 << 0) -#define PLX9050_LINTI1_ACTIVE_HIGH (1 << 1) -#define PLX9050_LINTI1_STATUS (1 << 2) -#define PLX9050_LINTI2_ENABLE (1 << 3) -#define PLX9050_LINTI2_ACTIVE_HIGH (1 << 4) -#define PLX9050_LINTI2_STATUS (1 << 5) -#define PLX9050_PCI_INTERRUPT_ENABLE (1 << 6) -#define PLX9050_SOFTWARE_INTERRUPT (1 << 7) - static void plx9050_interrupt_control(unsigned long io_base, bool LINTi1_enable, bool LINTi1_active_high, @@ -457,47 +160,33 @@ static void plx9050_interrupt_control(unsigned long io_base, int flags = 0; if (LINTi1_enable) - flags |= PLX9050_LINTI1_ENABLE; + flags |= PLX9052_INTCSR_LI1ENAB; if (LINTi1_active_high) - flags |= PLX9050_LINTI1_ACTIVE_HIGH; + flags |= PLX9052_INTCSR_LI1POL; if (LINTi2_enable) - flags |= PLX9050_LINTI2_ENABLE; + flags |= PLX9052_INTCSR_LI2ENAB; if (LINTi2_active_high) - flags |= PLX9050_LINTI2_ACTIVE_HIGH; + flags |= PLX9052_INTCSR_LI2POL; if (interrupt_enable) - flags |= PLX9050_PCI_INTERRUPT_ENABLE; + flags |= PLX9052_INTCSR_PCIENAB; - outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL); + outb(flags, io_base + PLX9052_INTCSR); } -/* ------------------------------------------------------------------ */ -/* MISCELLANEOUS SECTION */ -/* ------------------------------------------------------------------ */ - -/* 8254 timer */ - static void pci9111_timer_set(struct comedi_device *dev) { - pci9111_8254_control_set(PCI9111_8254_COUNTER_0 | - PCI9111_8254_READ_LOAD_LSB_MSB | - PCI9111_8254_MODE_0 | - PCI9111_8254_BINARY_COUNTER); - - pci9111_8254_control_set(PCI9111_8254_COUNTER_1 | - PCI9111_8254_READ_LOAD_LSB_MSB | - PCI9111_8254_MODE_2 | - PCI9111_8254_BINARY_COUNTER); + struct pci9111_private_data *dev_private = dev->private; + unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG; - pci9111_8254_control_set(PCI9111_8254_COUNTER_2 | - PCI9111_8254_READ_LOAD_LSB_MSB | - PCI9111_8254_MODE_2 | - PCI9111_8254_BINARY_COUNTER); + i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY); udelay(1); - pci9111_8254_counter_2_set(dev_private->timer_divisor_2); - pci9111_8254_counter_1_set(dev_private->timer_divisor_1); + i8254_write(timer_base, 1, 2, dev_private->div2); + i8254_write(timer_base, 1, 1, dev_private->div1); } enum pci9111_trigger_sources { @@ -511,47 +200,55 @@ static void pci9111_trigger_source_set(struct comedi_device *dev, { int flags; - flags = pci9111_trigger_and_autoscan_get() & 0x09; + /* Read the current trigger mode control bits */ + flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); + /* Mask off the EITS and TPST bits */ + flags &= 0x9; switch (source) { case software: - flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER; break; case timer_pacer: - flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER; + flags |= PCI9111_AI_TRIG_CTRL_TPST; break; case external: - flags |= PCI9111_EITS_EXTERNAL; + flags |= PCI9111_AI_TRIG_CTRL_ETIS; break; } - pci9111_trigger_and_autoscan_set(flags); + outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); } static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger) { int flags; - flags = pci9111_trigger_and_autoscan_get() & 0x07; + /* Read the current trigger mode control bits */ + flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); + /* Mask off the PTRG bit */ + flags &= 0x7; if (pretrigger) - flags |= PCI9111_PTRG_ON; + flags |= PCI9111_AI_TRIG_CTRL_PTRG; - pci9111_trigger_and_autoscan_set(flags); + outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); } static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan) { int flags; - flags = pci9111_trigger_and_autoscan_get() & 0x0e; + /* Read the current trigger mode control bits */ + flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); + /* Mask off the ASCAN bit */ + flags &= 0xe; if (autoscan) - flags |= PCI9111_ASCAN_ON; + flags |= PCI9111_AI_TRIG_CTRL_ASCAN; - pci9111_trigger_and_autoscan_set(flags); + outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); } enum pci9111_ISC0_sources { @@ -570,30 +267,39 @@ static void pci9111_interrupt_source_set(struct comedi_device *dev, { int flags; - flags = pci9111_interrupt_and_fifo_get() & 0x04; + /* Read the current interrupt control bits */ + flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); + /* Shift the bits so they are compatible with the write register */ + flags >>= 4; + /* Mask off the ISCx bits */ + flags &= 0xc0; + /* Now set the new ISCx bits */ if (irq_0_source == irq_on_fifo_half_full) - flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL; + flags |= PCI9111_INT_CTRL_ISC0; if (irq_1_source == irq_on_external_trigger) - flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG; + flags |= PCI9111_INT_CTRL_ISC1; - pci9111_interrupt_and_fifo_set(flags); + outb(flags, dev->iobase + PCI9111_INT_CTRL_REG); } -/* ------------------------------------------------------------------ */ -/* HARDWARE TRIGGERED ANALOG INPUT SECTION */ -/* ------------------------------------------------------------------ */ - -/* Cancel analog input autoscan */ +static void pci9111_fifo_reset(struct comedi_device *dev) +{ + unsigned long int_ctrl_reg = dev->iobase + PCI9111_INT_CTRL_REG; -#undef AI_DO_CMD_DEBUG + /* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */ + outb(0, int_ctrl_reg); + outb(PCI9111_INT_CTRL_FFEN, int_ctrl_reg); + outb(0, int_ctrl_reg); +} static int pci9111_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - /* Disable interrupts */ + struct pci9111_private_data *dev_private = dev->private; + /* Disable interrupts */ plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, true, false); @@ -601,344 +307,210 @@ static int pci9111_ai_cancel(struct comedi_device *dev, pci9111_autoscan_set(dev, false); - pci9111_fifo_reset(); - -#ifdef AI_DO_CMD_DEBUG - printk(PCI9111_DRIVER_NAME ": ai_cancel\n"); -#endif + pci9111_fifo_reset(dev); return 0; } -/* Test analog input command */ - -#define pci9111_check_trigger_src(src, flags) do { \ - tmp = src; \ - src &= flags; \ - if (!src || tmp != src) \ - error++; \ - } while (false); - -static int -pci9111_ai_do_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int pci9111_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - int tmp; - int error = 0; - int range, reference; + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; - struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr; - - /* Step 1 : check if trigger are trivialy valid */ - pci9111_check_trigger_src(cmd->start_src, TRIG_NOW); - pci9111_check_trigger_src(cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); - pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT); - pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT); - pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE); + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); - if (error) - return 1; - - /* step 2 : make sure trigger sources are unique and mutually - * compatible */ + if (chan != i) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels,counting upwards from 0\n"); + return -EINVAL; + } - if (cmd->start_src != TRIG_NOW) - error++; + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } - if ((cmd->scan_begin_src != TRIG_TIMER) && - (cmd->scan_begin_src != TRIG_FOLLOW) && - (cmd->scan_begin_src != TRIG_EXT)) - error++; + if (aref != aref0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same reference\n"); + return -EINVAL; + } + } - if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT)) - error++; - if ((cmd->convert_src == TRIG_TIMER) && - !((cmd->scan_begin_src == TRIG_TIMER) || - (cmd->scan_begin_src == TRIG_FOLLOW))) - error++; - if ((cmd->convert_src == TRIG_EXT) && - !((cmd->scan_begin_src == TRIG_EXT) || - (cmd->scan_begin_src == TRIG_FOLLOW))) - error++; + return 0; +} +static int pci9111_ai_do_cmd_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + struct pci9111_private_data *dev_private = dev->private; + int 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_FOLLOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, + TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; - if (cmd->scan_end_src != TRIG_COUNT) - error++; - if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE)) - error++; + /* Step 2a : make sure trigger sources are unique */ - if (error) - return 2; + 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 3 : make sure arguments are trivialy compatible */ + /* Step 2b : and mutually compatible */ - if (cmd->chanlist_len < 1) { - cmd->chanlist_len = 1; - error++; + if (cmd->scan_begin_src != TRIG_FOLLOW) { + if (cmd->scan_begin_src != cmd->convert_src) + err |= -EINVAL; } - if (cmd->chanlist_len > board->ai_channel_nbr) { - cmd->chanlist_len = board->ai_channel_nbr; - error++; - } + if (err) + return 2; - if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) { - cmd->start_arg = 0; - error++; - } + /* Step 3: check if arguments are trivially valid */ - if ((cmd->convert_src == TRIG_TIMER) && - (cmd->convert_arg < board->ai_acquisition_period_min_ns)) { - cmd->convert_arg = board->ai_acquisition_period_min_ns; - error++; - } - if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) { - cmd->convert_arg = 0; - error++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if ((cmd->scan_begin_src == TRIG_TIMER) && - (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) { - cmd->scan_begin_arg = board->ai_acquisition_period_min_ns; - error++; - } - if ((cmd->scan_begin_src == TRIG_FOLLOW) - && (cmd->scan_begin_arg != 0)) { - cmd->scan_begin_arg = 0; - error++; - } - if ((cmd->scan_begin_src == TRIG_EXT) && (cmd->scan_begin_arg != 0)) { - cmd->scan_begin_arg = 0; - error++; - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + PCI9111_AI_ACQUISITION_PERIOD_MIN_NS); + else /* TRIG_EXT */ + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - if ((cmd->scan_end_src == TRIG_COUNT) && - (cmd->scan_end_arg != cmd->chanlist_len)) { - cmd->scan_end_arg = cmd->chanlist_len; - error++; - } + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + PCI9111_AI_ACQUISITION_PERIOD_MIN_NS); + else /* TRIG_FOLLOW || TRIG_EXT */ + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - if ((cmd->stop_src == TRIG_COUNT) && (cmd->stop_arg < 1)) { - cmd->stop_arg = 1; - error++; - } - if ((cmd->stop_src == TRIG_NONE) && (cmd->stop_arg != 0)) { - cmd->stop_arg = 0; - error++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - if (error) + if (err) return 3; - /* Step 4 : fix up any arguments */ + /* Step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, - &(dev_private->timer_divisor_1), - &(dev_private->timer_divisor_2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - error++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &dev_private->div1, + &dev_private->div2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } - /* There's only one timer on this card, so the scan_begin timer must */ - /* be a multiple of chanlist_len*convert_arg */ + /* + * There's only one timer on this card, so the scan_begin timer + * must be a multiple of chanlist_len*convert_arg + */ if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->chanlist_len * cmd->convert_arg; - unsigned int scan_begin_min; - unsigned int scan_begin_arg; - unsigned int scan_factor; - - scan_begin_min = cmd->chanlist_len * cmd->convert_arg; - - if (cmd->scan_begin_arg != scan_begin_min) { - if (scan_begin_min < cmd->scan_begin_arg) { - scan_factor = - cmd->scan_begin_arg / scan_begin_min; - scan_begin_arg = scan_factor * scan_begin_min; - if (cmd->scan_begin_arg != scan_begin_arg) { - cmd->scan_begin_arg = scan_begin_arg; - error++; - } - } else { - cmd->scan_begin_arg = scan_begin_min; - error++; - } - } + if (arg < cmd->scan_begin_arg) + arg *= (cmd->scan_begin_arg / arg); + + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } - if (error) + if (err) return 4; - /* Step 5 : check channel list */ - - if (cmd->chanlist) { - - range = CR_RANGE(cmd->chanlist[0]); - reference = CR_AREF(cmd->chanlist[0]); - - if (cmd->chanlist_len > 1) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - comedi_error(dev, - "entries in chanlist must be consecutive " - "channels,counting upwards from 0\n"); - error++; - } - if (CR_RANGE(cmd->chanlist[i]) != range) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - error++; - } - if (CR_AREF(cmd->chanlist[i]) != reference) { - comedi_error(dev, - "entries in chanlist must all have the same reference\n"); - error++; - } - } - } else { - if ((CR_CHAN(cmd->chanlist[0]) > - (board->ai_channel_nbr - 1)) - || (CR_CHAN(cmd->chanlist[0]) < 0)) { - comedi_error(dev, - "channel number is out of limits\n"); - error++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci9111_ai_check_chanlist(dev, s, cmd); - if (error) + if (err) return 5; return 0; } -/* Analog input command */ - static int pci9111_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *subdevice) + struct comedi_subdevice *s) { - struct comedi_cmd *async_cmd = &subdevice->async->cmd; + struct pci9111_private_data *dev_private = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - if (!dev->irq) { - comedi_error(dev, - "no irq assigned for PCI9111, cannot do hardware conversion"); - return -1; - } /* Set channel scan limit */ /* PCI9111 allows only scanning from channel 0 to channel n */ /* TODO: handle the case of an external multiplexer */ - if (async_cmd->chanlist_len > 1) { - pci9111_ai_channel_set((async_cmd->chanlist_len) - 1); + if (cmd->chanlist_len > 1) { + outb(cmd->chanlist_len - 1, + dev->iobase + PCI9111_AI_CHANNEL_REG); pci9111_autoscan_set(dev, true); } else { - pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0])); + outb(CR_CHAN(cmd->chanlist[0]), + dev->iobase + PCI9111_AI_CHANNEL_REG); pci9111_autoscan_set(dev, false); } /* Set gain */ /* This is the same gain on every channel */ - pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0])); + outb(CR_RANGE(cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, + dev->iobase + PCI9111_AI_RANGE_STAT_REG); /* Set counter */ - - switch (async_cmd->stop_src) { - case TRIG_COUNT: - dev_private->stop_counter = - async_cmd->stop_arg * async_cmd->chanlist_len; - dev_private->stop_is_none = 0; - break; - - case TRIG_NONE: + if (cmd->stop_src == TRIG_COUNT) + dev_private->stop_counter = cmd->stop_arg * cmd->chanlist_len; + else /* TRIG_NONE */ dev_private->stop_counter = 0; - dev_private->stop_is_none = 1; - break; - - default: - comedi_error(dev, "Invalid stop trigger"); - return -1; - } /* Set timer pacer */ - dev_private->scan_delay = 0; - switch (async_cmd->convert_src) { - case TRIG_TIMER: - i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, - &(dev_private->timer_divisor_1), - &(dev_private->timer_divisor_2), - &(async_cmd->convert_arg), - async_cmd-> - flags & TRIG_ROUND_MASK); -#ifdef AI_DO_CMD_DEBUG - printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n", - dev_private->timer_divisor_1, - dev_private->timer_divisor_2); -#endif - + if (cmd->convert_src == TRIG_TIMER) { pci9111_trigger_source_set(dev, software); pci9111_timer_set(dev); - pci9111_fifo_reset(); + pci9111_fifo_reset(dev); pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, irq_on_timer_tick); pci9111_trigger_source_set(dev, timer_pacer); plx9050_interrupt_control(dev_private->lcr_io_base, true, true, false, true, true); - if (async_cmd->scan_begin_src == TRIG_TIMER) { - dev_private->scan_delay = - (async_cmd->scan_begin_arg / - (async_cmd->convert_arg * - async_cmd->chanlist_len)) - 1; + if (cmd->scan_begin_src == TRIG_TIMER) { + dev_private->scan_delay = (cmd->scan_begin_arg / + (cmd->convert_arg * cmd->chanlist_len)) - 1; } - - break; - - case TRIG_EXT: - + } else { /* TRIG_EXT */ pci9111_trigger_source_set(dev, external); - pci9111_fifo_reset(); + pci9111_fifo_reset(dev); pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, irq_on_timer_tick); plx9050_interrupt_control(dev_private->lcr_io_base, true, true, false, true, true); - break; - - default: - comedi_error(dev, "Invalid convert trigger"); - return -1; } dev_private->stop_counter *= (1 + dev_private->scan_delay); - dev_private->chanlist_len = async_cmd->chanlist_len; dev_private->chunk_counter = 0; - dev_private->chunk_num_samples = - dev_private->chanlist_len * (1 + dev_private->scan_delay); - -#ifdef AI_DO_CMD_DEBUG - printk(PCI9111_DRIVER_NAME ": start interruptions!\n"); - printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n", - pci9111_trigger_and_autoscan_get()); - printk(PCI9111_DRIVER_NAME ": irq source = %2x\n", - pci9111_interrupt_and_fifo_get()); - printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n"); - printk(PCI9111_DRIVER_NAME ": stop counter = %d\n", - dev_private->stop_counter); - printk(PCI9111_DRIVER_NAME ": scan delay = %d\n", - dev_private->scan_delay); - printk(PCI9111_DRIVER_NAME ": chanlist_len = %d\n", - dev_private->chanlist_len); - printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n", - dev_private->chunk_num_samples); -#endif + dev_private->chunk_num_samples = cmd->chanlist_len * + (1 + dev_private->scan_delay); return 0; } @@ -948,34 +520,83 @@ static void pci9111_ai_munge(struct comedi_device *dev, unsigned int num_bytes, unsigned int start_chan_index) { - unsigned int i, num_samples = num_bytes / sizeof(short); - short *array = data; - int resolution = - ((struct pci9111_board *)dev->board_ptr)->ai_resolution; - - for (i = 0; i < num_samples; i++) { - if (resolution == PCI9111_HR_AI_RESOLUTION) - array[i] = - (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^ - PCI9111_HR_AI_RESOLUTION_2_CMP_BIT; - else - array[i] = - ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^ - PCI9111_AI_RESOLUTION_2_CMP_BIT; - } + unsigned short *array = data; + unsigned int maxdata = s->maxdata; + unsigned int invert = (maxdata + 1) >> 1; + unsigned int shift = (maxdata == 0xffff) ? 0 : 4; + unsigned int num_samples = num_bytes / sizeof(short); + unsigned int i; + + for (i = 0; i < num_samples; i++) + array[i] = ((array[i] >> shift) & maxdata) ^ invert; } -/* ------------------------------------------------------------------ */ -/* INTERRUPT SECTION */ -/* ------------------------------------------------------------------ */ +static void pci9111_handle_fifo_half_full(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci9111_private_data *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int total = 0; + unsigned int samples; + + if (cmd->stop_src == TRIG_COUNT && + PCI9111_FIFO_HALF_SIZE > devpriv->stop_counter) + samples = devpriv->stop_counter; + else + samples = PCI9111_FIFO_HALF_SIZE; + + insw(dev->iobase + PCI9111_AI_FIFO_REG, + devpriv->ai_bounce_buffer, samples); + + if (devpriv->scan_delay < 1) { + total = cfc_write_array_to_buffer(s, + devpriv->ai_bounce_buffer, + samples * sizeof(short)); + } else { + unsigned int pos = 0; + unsigned int to_read; -#undef INTERRUPT_DEBUG + while (pos < samples) { + if (devpriv->chunk_counter < cmd->chanlist_len) { + to_read = cmd->chanlist_len - + devpriv->chunk_counter; + + if (to_read > samples - pos) + to_read = samples - pos; + + total += cfc_write_array_to_buffer(s, + devpriv->ai_bounce_buffer + pos, + to_read * sizeof(short)); + } else { + to_read = devpriv->chunk_num_samples - + devpriv->chunk_counter; + + if (to_read > samples - pos) + to_read = samples - pos; + + total += to_read * sizeof(short); + } + + pos += to_read; + devpriv->chunk_counter += to_read; + + if (devpriv->chunk_counter >= + devpriv->chunk_num_samples) + devpriv->chunk_counter = 0; + } + } + + devpriv->stop_counter -= total / sizeof(short); +} static irqreturn_t pci9111_interrupt(int irq, void *p_device) { struct comedi_device *dev = p_device; - struct comedi_subdevice *subdevice = dev->read_subdev; + struct pci9111_private_data *dev_private = dev->private; + struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async; + struct comedi_cmd *cmd; + unsigned int status; unsigned long irq_flags; unsigned char intcsr; @@ -985,279 +606,168 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) return IRQ_NONE; } - async = subdevice->async; + async = s->async; + cmd = &async->cmd; spin_lock_irqsave(&dev->spinlock, irq_flags); /* Check if we are source of interrupt */ - intcsr = inb(dev_private->lcr_io_base + - PLX9050_REGISTER_INTERRUPT_CONTROL); - if (!(((intcsr & PLX9050_PCI_INTERRUPT_ENABLE) != 0) - && (((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) - == (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) - || ((intcsr & (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS)) - == (PLX9050_LINTI2_ENABLE | PLX9050_LINTI2_STATUS))))) { + intcsr = inb(dev_private->lcr_io_base + PLX9052_INTCSR); + if (!(((intcsr & PLX9052_INTCSR_PCIENAB) != 0) && + (((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) || + ((intcsr & PCI9111_LI2_ACTIVE) == PCI9111_LI2_ACTIVE)))) { /* Not the source of the interrupt. */ - /* (N.B. not using PLX9050_SOFTWARE_INTERRUPT) */ + /* (N.B. not using PLX9052_INTCSR_SOFTINT) */ spin_unlock_irqrestore(&dev->spinlock, irq_flags); return IRQ_NONE; } - if ((intcsr & (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) == - (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) { + if ((intcsr & PCI9111_LI1_ACTIVE) == PCI9111_LI1_ACTIVE) { /* Interrupt comes from fifo_half-full signal */ - if (pci9111_is_fifo_full()) { + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + + /* '0' means FIFO is full, data may have been lost */ + if (!(status & PCI9111_AI_STAT_FF_FF)) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); - pci9111_interrupt_clear(); - pci9111_ai_cancel(dev, subdevice); + outb(0, dev->iobase + PCI9111_INT_CLR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, subdevice); + cfc_handle_events(dev, s); return IRQ_HANDLED; } - if (pci9111_is_fifo_half_full()) { - unsigned int num_samples; - unsigned int bytes_written = 0; - -#ifdef INTERRUPT_DEBUG - printk(PCI9111_DRIVER_NAME ": fifo is half full\n"); -#endif - - num_samples = - PCI9111_FIFO_HALF_SIZE > - dev_private->stop_counter - && !dev_private-> - stop_is_none ? dev_private->stop_counter : - PCI9111_FIFO_HALF_SIZE; - insw(PCI9111_IO_BASE + PCI9111_REGISTER_AD_FIFO_VALUE, - dev_private->ai_bounce_buffer, num_samples); - - if (dev_private->scan_delay < 1) { - bytes_written = - cfc_write_array_to_buffer(subdevice, - dev_private-> - ai_bounce_buffer, - num_samples * - sizeof(short)); - } else { - int position = 0; - int to_read; - - while (position < num_samples) { - if (dev_private->chunk_counter < - dev_private->chanlist_len) { - to_read = - dev_private->chanlist_len - - dev_private->chunk_counter; - - if (to_read > - num_samples - position) - to_read = - num_samples - - position; - - bytes_written += - cfc_write_array_to_buffer - (subdevice, - dev_private->ai_bounce_buffer - + position, - to_read * sizeof(short)); - } else { - to_read = - dev_private->chunk_num_samples - - - dev_private->chunk_counter; - if (to_read > - num_samples - position) - to_read = - num_samples - - position; - - bytes_written += - sizeof(short) * to_read; - } - - position += to_read; - dev_private->chunk_counter += to_read; - - if (dev_private->chunk_counter >= - dev_private->chunk_num_samples) - dev_private->chunk_counter = 0; - } - } - - dev_private->stop_counter -= - bytes_written / sizeof(short); - } + /* '0' means FIFO is half-full */ + if (!(status & PCI9111_AI_STAT_FF_HF)) + pci9111_handle_fifo_half_full(dev, s); } - if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) { + if (cmd->stop_src == TRIG_COUNT && dev_private->stop_counter == 0) async->events |= COMEDI_CB_EOA; - pci9111_ai_cancel(dev, subdevice); - } - /* Very important, otherwise another interrupt request will be inserted - * and will cause driver hangs on processing interrupt event. */ - - pci9111_interrupt_clear(); + outb(0, dev->iobase + PCI9111_INT_CLR_REG); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - comedi_event(dev, subdevice); + cfc_handle_events(dev, s); return IRQ_HANDLED; } -/* ------------------------------------------------------------------ */ -/* INSTANT ANALOG INPUT OUTPUT SECTION */ -/* ------------------------------------------------------------------ */ - -/* analog instant input */ +static int pci9111_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; -#undef AI_INSN_DEBUG + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + if (status & PCI9111_AI_STAT_FF_EF) + return 0; + return -EBUSY; +} static int pci9111_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *subdevice, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int resolution = - ((struct pci9111_board *)dev->board_ptr)->ai_resolution; - - int timeout, i; - -#ifdef AI_INSN_DEBUG - printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n", - CR_CHAN((&insn->chanspec)[0]), - CR_RANGE((&insn->chanspec)[0]), insn->n); -#endif + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int maxdata = s->maxdata; + unsigned int invert = (maxdata + 1) >> 1; + unsigned int shift = (maxdata == 0xffff) ? 0 : 4; + unsigned int status; + int ret; + int i; - pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0])); + outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG); - if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0])) - pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0])); + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + if ((status & PCI9111_AI_RANGE_MASK) != range) { + outb(range & PCI9111_AI_RANGE_MASK, + dev->iobase + PCI9111_AI_RANGE_STAT_REG); + } - pci9111_fifo_reset(); + pci9111_fifo_reset(dev); for (i = 0; i < insn->n; i++) { - pci9111_software_trigger(); - - timeout = PCI9111_AI_INSTANT_READ_TIMEOUT; + /* Generate a software trigger */ + outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG); - while (timeout--) { - if (!pci9111_is_fifo_empty()) - goto conversion_done; + ret = comedi_timeout(dev, s, insn, pci9111_ai_eoc, 0); + if (ret) { + pci9111_fifo_reset(dev); + return ret; } - comedi_error(dev, "A/D read timeout"); - data[i] = 0; - pci9111_fifo_reset(); - return -ETIME; - -conversion_done: - - if (resolution == PCI9111_HR_AI_RESOLUTION) - data[i] = pci9111_hr_ai_get_data(); - else - data[i] = pci9111_ai_get_data(); + data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG); + data[i] = ((data[i] >> shift) & maxdata) ^ invert; } -#ifdef AI_INSN_DEBUG - printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n", - pci9111_ai_channel_get(), - pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get()); -#endif - return i; } -/* Analog instant output */ - -static int -pci9111_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int pci9111_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct pci9111_private_data *dev_private = dev->private; + unsigned int val = 0; int i; for (i = 0; i < insn->n; i++) { - pci9111_ao_set_data(data[i]); - dev_private->ao_readback = data[i]; + val = data[i]; + outw(val, dev->iobase + PCI9111_AO_REG); } + dev_private->ao_readback = val; - return i; + return insn->n; } -/* Analog output readback */ - static int pci9111_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct pci9111_private_data *dev_private = dev->private; int i; for (i = 0; i < insn->n; i++) - data[i] = dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK; + data[i] = dev_private->ao_readback; - return i; + return insn->n; } -/* ------------------------------------------------------------------ */ -/* DIGITAL INPUT OUTPUT SECTION */ -/* ------------------------------------------------------------------ */ - -/* Digital inputs */ - static int pci9111_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *subdevice, - struct comedi_insn *insn, unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int bits; - - bits = pci9111_di_get_bits(); - data[1] = bits; + data[1] = inw(dev->iobase + PCI9111_DIO_REG); - return 2; + return insn->n; } -/* Digital outputs */ - static int pci9111_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *subdevice, - struct comedi_insn *insn, unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int bits; + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + PCI9111_DIO_REG); - /* Only set bits that have been masked */ - /* data[0] = mask */ - /* data[1] = bit state */ + data[1] = s->state; - data[0] &= PCI9111_DO_MASK; - - bits = subdevice->state; - bits &= ~data[0]; - bits |= data[0] & data[1]; - subdevice->state = bits; - - pci9111_do_set_bits(bits); - - data[1] = bits; - - return 2; + return insn->n; } -/* ------------------------------------------------------------------ */ -/* INITIALISATION SECTION */ -/* ------------------------------------------------------------------ */ - -/* Reset device */ - static int pci9111_reset(struct comedi_device *dev) { - /* Set trigger source to software */ + struct pci9111_private_data *dev_private = dev->private; + /* Set trigger source to software */ plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, true, false); @@ -1265,213 +775,129 @@ static int pci9111_reset(struct comedi_device *dev) pci9111_pretrigger_set(dev, false); pci9111_autoscan_set(dev, false); - /* Reset 8254 chip */ - - dev_private->timer_divisor_1 = 0; - dev_private->timer_divisor_2 = 0; - + /* Reset 8254 chip */ + dev_private->div1 = 0; + dev_private->div2 = 0; pci9111_timer_set(dev); return 0; } -/* Attach */ -/* - Register PCI device */ -/* - Declare device driver capability */ - -static int pci9111_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci9111_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - struct comedi_subdevice *subdevice; - unsigned long io_base, io_range, lcr_io_base, lcr_io_range; - struct pci_dev *pci_device = NULL; - int error, i; - const struct pci9111_board *board; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct pci9111_private_data *dev_private; + struct comedi_subdevice *s; + int ret; - if (alloc_private(dev, sizeof(struct pci9111_private_data)) < 0) + dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private)); + if (!dev_private) return -ENOMEM; - /* Probe the device to determine what device in the series it is. */ - - printk(KERN_ERR "comedi%d: " PCI9111_DRIVER_NAME " driver\n", - dev->minor); - - for_each_pci_dev(pci_device) { - if (pci_device->vendor == PCI_VENDOR_ID_ADLINK) { - for (i = 0; i < pci9111_board_nbr; i++) { - if (pci9111_boards[i].device_id == - pci_device->device) { - /* was a particular bus/slot - * requested? */ - if ((it->options[0] != 0) - || (it->options[1] != 0)) { - /* are we on the wrong - * bus/slot? */ - if (pci_device->bus->number != - it->options[0] - || - PCI_SLOT(pci_device->devfn) - != it->options[1]) { - continue; - } - } - - dev->board_ptr = pci9111_boards + i; - board = - (struct pci9111_board *) - dev->board_ptr; - dev_private->pci_device = pci_device; - goto found; - } - } - } - } - - printk(KERN_ERR - "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, it->options[0], it->options[1]); - return -EIO; - -found: - - printk(KERN_ERR "comedi%d: found %s (b:s:f=%d:%d:%d) , irq=%d\n", - dev->minor, - pci9111_boards[i].name, - pci_device->bus->number, - PCI_SLOT(pci_device->devfn), - PCI_FUNC(pci_device->devfn), pci_device->irq); - - /* TODO: Warn about non-tested boards. */ - - /* Read local configuration register base address - * [PCI_BASE_ADDRESS #1]. */ - lcr_io_base = pci_resource_start(pci_device, 1); - lcr_io_range = pci_resource_len(pci_device, 1); - - printk - ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n", - dev->minor, lcr_io_base, lcr_io_range); - - /* Enable PCI device and request regions */ - if (comedi_pci_enable(pci_device, PCI9111_DRIVER_NAME) < 0) { - printk - ("comedi%d: Failed to enable PCI device and request regions\n", - dev->minor); - return -EIO; - } - /* Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */ - - io_base = pci_resource_start(pci_device, 2); - io_range = pci_resource_len(pci_device, 2); - - printk(KERN_ERR "comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n", - dev->minor, io_base, io_range); - - dev->iobase = io_base; - dev->board_name = board->name; - dev_private->io_range = io_range; - dev_private->is_valid = 0; - dev_private->lcr_io_base = lcr_io_base; - dev_private->lcr_io_range = lcr_io_range; + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev_private->lcr_io_base = pci_resource_start(pcidev, 1); + dev->iobase = pci_resource_start(pcidev, 2); pci9111_reset(dev); - /* Irq setup */ + if (pcidev->irq) { + ret = request_irq(pcidev->irq, pci9111_interrupt, + IRQF_SHARED, dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } - dev->irq = 0; - if (pci_device->irq > 0) { - if (request_irq(pci_device->irq, pci9111_interrupt, - IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) { - printk(KERN_ERR - "comedi%d: unable to allocate irq %u\n", - dev->minor, pci_device->irq); - return -EINVAL; - } + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON; + s->n_chan = 16; + s->maxdata = 0xffff; + s->range_table = &pci9111_ai_range; + s->insn_read = pci9111_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = pci9111_ai_do_cmd_test; + s->do_cmd = pci9111_ai_do_cmd; + s->cancel = pci9111_ai_cancel; + s->munge = pci9111_ai_munge; } - dev->irq = pci_device->irq; - - /* TODO: Add external multiplexer setup (according to option[2]). */ - - error = alloc_subdevices(dev, 4); - if (error < 0) - return error; - - subdevice = dev->subdevices + 0; - dev->read_subdev = subdevice; - - subdevice->type = COMEDI_SUBD_AI; - subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; - - /* TODO: Add external multiplexer data */ - /* if (devpriv->usemux) { subdevice->n_chan = devpriv->usemux; } */ - /* else { subdevice->n_chan = this_board->n_aichan; } */ - - subdevice->n_chan = board->ai_channel_nbr; - subdevice->maxdata = board->ai_resolution_mask; - subdevice->len_chanlist = board->ai_channel_nbr; - subdevice->range_table = board->ai_range_list; - subdevice->cancel = pci9111_ai_cancel; - subdevice->insn_read = pci9111_ai_insn_read; - subdevice->do_cmdtest = pci9111_ai_do_cmd_test; - subdevice->do_cmd = pci9111_ai_do_cmd; - subdevice->munge = pci9111_ai_munge; - - subdevice = dev->subdevices + 1; - subdevice->type = COMEDI_SUBD_AO; - subdevice->subdev_flags = SDF_WRITABLE | SDF_COMMON; - subdevice->n_chan = board->ao_channel_nbr; - subdevice->maxdata = board->ao_resolution_mask; - subdevice->len_chanlist = board->ao_channel_nbr; - subdevice->range_table = board->ao_range_list; - subdevice->insn_write = pci9111_ao_insn_write; - subdevice->insn_read = pci9111_ao_insn_read; - - subdevice = dev->subdevices + 2; - subdevice->type = COMEDI_SUBD_DI; - subdevice->subdev_flags = SDF_READABLE; - subdevice->n_chan = PCI9111_DI_CHANNEL_NBR; - subdevice->maxdata = 1; - subdevice->range_table = &range_digital; - subdevice->insn_bits = pci9111_di_insn_bits; - - subdevice = dev->subdevices + 3; - subdevice->type = COMEDI_SUBD_DO; - subdevice->subdev_flags = SDF_READABLE | SDF_WRITABLE; - subdevice->n_chan = PCI9111_DO_CHANNEL_NBR; - subdevice->maxdata = 1; - subdevice->range_table = &range_digital; - subdevice->insn_bits = pci9111_do_insn_bits; - - dev_private->is_valid = 1; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_COMMON; + s->n_chan = 1; + s->maxdata = 0x0fff; + s->len_chanlist = 1; + s->range_table = &range_bipolar10; + s->insn_write = pci9111_ao_insn_write; + s->insn_read = pci9111_ao_insn_read; + + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pci9111_di_insn_bits; + + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pci9111_do_insn_bits; return 0; } -/* Detach */ - -static int pci9111_detach(struct comedi_device *dev) +static void pci9111_detach(struct comedi_device *dev) { - /* Reset device */ - - if (dev->private != NULL) { - if (dev_private->is_valid) - pci9111_reset(dev); - - } - /* Release previously allocated irq */ - + if (dev->iobase) + pci9111_reset(dev); if (dev->irq != 0) free_irq(dev->irq, dev); + comedi_pci_disable(dev); +} - if (dev_private != NULL && dev_private->pci_device != NULL) { - if (dev->iobase) - comedi_pci_disable(dev_private->pci_device); - pci_dev_put(dev_private->pci_device); - } +static struct comedi_driver adl_pci9111_driver = { + .driver_name = "adl_pci9111", + .module = THIS_MODULE, + .auto_attach = pci9111_auto_attach, + .detach = pci9111_detach, +}; - return 0; +static int pci9111_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &adl_pci9111_driver, + id->driver_data); } +static const struct pci_device_id pci9111_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HR_DEVICE_ID) }, + /* { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI9111_HG_DEVICE_ID) }, */ + { 0 } +}; +MODULE_DEVICE_TABLE(pci, pci9111_pci_table); + +static struct pci_driver adl_pci9111_pci_driver = { + .name = "adl_pci9111", + .id_table = pci9111_pci_table, + .probe = pci9111_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adl_pci9111_driver, adl_pci9111_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index 08b71d9974b..59a65cbc6db 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -62,38 +62,41 @@ Configuration options: 256|=ignore nFull - A/D FIFO Full status */ -#include "../comedidev.h" +/* + * FIXME + * + * All the supported boards have the same PCI vendor and device IDs, so + * auto-attachment of PCI devices will always find the first board type. + * + * Perhaps the boards have different subdevice IDs that we could use to + * distinguish them? + * + * Need some device attributes so the board type can be corrected after + * attachment if necessary, and possibly to set other options supported by + * manual attachment. + */ + +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> #include <linux/gfp.h> #include <linux/interrupt.h> +#include <linux/io.h> + +#include "../comedidev.h" #include "amcc_s5933.h" #include "8253.h" -#include "comedi_pci.h" #include "comedi_fc.h" -#define PCI_VENDOR_ID_AMCC 0x10e8 - /* paranoid checks are broken */ #undef PCI9118_PARANOIDCHECK /* * if defined, then is used code which control * correct channel number on every 12 bit sample */ -#undef PCI9118_EXTDEBUG /* - * if defined then driver prints - * a lot of messages - */ - -#undef DPRINTK -#ifdef PCI9118_EXTDEBUG -#define DPRINTK(fmt, args...) printk(fmt, ## args) -#else -#define DPRINTK(fmt, args...) -#endif - -#define IORANGE_9118 64 /* I hope */ +#define IORANGE_9118 64 /* I hope */ #define PCI9118_CHANLEN 255 /* * len of chanlist, some source say 256, * but reality looks like 255 :-( @@ -191,28 +194,30 @@ Configuration options: #define EXTTRG_AI 0 /* ext trg is used by AI */ -static const struct comedi_lrange range_pci9118dg_hr = { 8, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } +static const struct comedi_lrange range_pci9118dg_hr = { + 8, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_pci9118hg = { 8, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01) - } +static const struct comedi_lrange range_pci9118hg = { + 8, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; #define PCI9118_BIPOLAR_RANGES 4 /* @@ -220,14 +225,9 @@ static const struct comedi_lrange range_pci9118hg = { 8, { * of BIP/UNI ranges */ -static int pci9118_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci9118_detach(struct comedi_device *dev); - struct boardtype { const char *name; /* board name */ - int vendor_id; /* PCI vendor a device ID of card */ - int device_id; + 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 */ @@ -251,85 +251,64 @@ struct boardtype { }; -static DEFINE_PCI_DEVICE_TABLE(pci9118_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci9118_pci_table); - static const struct boardtype boardtypes[] = { - {"pci9118dg", PCI_VENDOR_ID_AMCC, 0x80d9, - AMCC_OP_REG_SIZE, IORANGE_9118, - 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, - &range_pci9118dg_hr, &range_bipolar10, - 3000, 12, 512}, - {"pci9118hg", PCI_VENDOR_ID_AMCC, 0x80d9, - AMCC_OP_REG_SIZE, IORANGE_9118, - 16, 8, 256, PCI9118_CHANLEN, 2, 0x0fff, 0x0fff, - &range_pci9118hg, &range_bipolar10, - 3000, 12, 512}, - {"pci9118hr", PCI_VENDOR_ID_AMCC, 0x80d9, - AMCC_OP_REG_SIZE, IORANGE_9118, - 16, 8, 256, PCI9118_CHANLEN, 2, 0xffff, 0x0fff, - &range_pci9118dg_hr, &range_bipolar10, - 10000, 40, 512}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) - -static struct comedi_driver driver_pci9118 = { - .driver_name = "adl_pci9118", - .module = THIS_MODULE, - .attach = pci9118_attach, - .detach = pci9118_detach, - .num_names = n_boardtypes, - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), + { + .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, + }, { + .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, + }, { + .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, + }, }; -static int __devinit driver_pci9118_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_pci9118.driver_name); -} - -static void __devexit driver_pci9118_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_pci9118_pci_driver = { - .id_table = pci9118_pci_table, - .probe = &driver_pci9118_pci_probe, - .remove = __devexit_p(&driver_pci9118_pci_remove) -}; - -static int __init driver_pci9118_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pci9118); - if (retval < 0) - return retval; - - driver_pci9118_pci_driver.name = (char *)driver_pci9118.driver_name; - return pci_register_driver(&driver_pci9118_pci_driver); -} - -static void __exit driver_pci9118_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci9118_pci_driver); - comedi_driver_unregister(&driver_pci9118); -} - -module_init(driver_pci9118_init_module); -module_exit(driver_pci9118_cleanup_module); - struct pci9118_private { unsigned long iobase_a; /* base+size for AMCC chip */ unsigned int master; /* master capable */ - struct pci_dev *pcidev; /* ptr to actual pcidev */ unsigned int usemux; /* we want to use external multiplexor! */ #ifdef PCI9118_PARANOIDCHECK unsigned short chanlist[PCI9118_CHANLEN + 1]; /* @@ -341,14 +320,9 @@ struct pci9118_private { unsigned char AdControlReg; /* A/D control register */ unsigned char IntControlReg; /* Interrupt control register */ unsigned char AdFunctionReg; /* A/D function register */ - char valid; /* driver is ok */ char ai_neverending; /* we do unlimited AI */ - unsigned int i8254_osc_base; /* frequence of onboard oscilator */ unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_buf_ptr; /* data buffer ptr in samples */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int ai_n_scanlen; /* len of actual scanlist */ unsigned int ai_n_realscanlen; /* * what we must transfer for one * outgoing scan include front/back adds @@ -362,9 +336,6 @@ struct pci9118_private { * how many channels we must add * before scan to satisfy DMA? */ - unsigned int *ai_chanlist; /* actual chanlist */ - unsigned int ai_timer1; - unsigned int ai_timer2; unsigned int ai_flags; char ai12_startstop; /* * measure can start/stop @@ -374,13 +345,10 @@ struct pci9118_private { * divisors for start of measure * on external start */ - unsigned int ai_data_len; - short *ai_data; - short ao_data[2]; /* data output buffer */ - unsigned int ai_scans; /* number of scans to do */ - char dma_doublebuf; /* we can use double buffring */ + unsigned short ao_data[2]; /* data output buffer */ + char dma_doublebuf; /* we can use double buffering */ unsigned int dma_actbuf; /* which buffer is used now */ - short *dmabuf_virt[2]; /* + unsigned short *dmabuf_virt[2]; /* * pointers to begin of * DMA buffer */ @@ -394,31 +362,12 @@ struct pci9118_private { */ unsigned int dmabuf_used_size[2]; /* which size was truly used */ unsigned int dmabuf_panic_size[2]; - unsigned int dmabuf_samples[2]; /* size in samples */ int dmabuf_pages[2]; /* number of pages in buffer */ - unsigned char cnt0_users; /* - * bit field of 8254 CNT0 users - * (0-unused, 1-AO, 2-DI, 3-DO) - */ unsigned char exttrg_users; /* * bit field of external trigger * users(0-AI, 1-AO, 2-DI, 3-DO) */ - unsigned int cnt0_divisor; /* actual CNT0 divisor */ - void (*int_ai_func) (struct comedi_device *, struct comedi_subdevice *, - unsigned short, - unsigned int, - unsigned short); /* - * ptr to actual interrupt - * AI function - */ - unsigned char ai16bits; /* =1 16 bit card */ unsigned char usedma; /* =1 use DMA transfer and not INT */ - unsigned char useeoshandle; /* - * =1 change WAKE_EOS DMA transfer - * to fit on every second - */ - unsigned char usessh; /* =1 turn on S&H support */ int softsshdelay; /* * >0 use software S&H, * numer is requested delay in ns @@ -433,47 +382,173 @@ struct pci9118_private { */ unsigned int ai_maskerr; /* which warning was printed */ unsigned int ai_maskharderr; /* on which error bits stops */ - unsigned int ai_inttrig_start; /* TRIG_INT for start */ }; -#define devpriv ((struct pci9118_private *)dev->private) -#define this_board ((struct boardtype *)dev->board_ptr) - -/* -============================================================================== -*/ - static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, - unsigned int *chanlist, int frontadd, - int backadd); + 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; + + /* correct channel and range number check itself comedi/range.c */ + if (n_chan < 1) { + comedi_error(dev, "range/channel list is empty!"); + return 0; + } + if ((frontadd + n_chan + backadd) > s->len_chanlist) { + comedi_error(dev, + "range/channel list is too long for actual configuration!\n"); + return 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 */ + if (n_chan > 1) + for (i = 1; i < n_chan; i++) { /* check S.E/diff */ + if ((CR_AREF(chanlist[i]) == AREF_DIFF) != + (differencial)) { + comedi_error(dev, + "Differencial and single ended " + "inputs can't be mixtured!"); + return 0; + } + if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) != + (bipolar)) { + comedi_error(dev, + "Bipolar and unipolar ranges " + "can't be mixtured!"); + return 0; + } + if (!devpriv->usemux && differencial && + (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) { + comedi_error(dev, + "If AREF_DIFF is used then is " + "available only first 8 channels!"); + return 0; + } + } + + 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, char eoshandle); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static int pci9118_reset(struct comedi_device *dev); -static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source); -static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source); -static int pci9118_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void pci9118_calc_divisors(char mode, 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, - char usessh, unsigned int chnsshfront); + int backadd, int usedma) +{ + 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 */ + + 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 */ + 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); + 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); + } + + 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); + } + } +#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) { - - int n, timeout; + struct pci9118_private *devpriv = dev->private; + int ret; + int n; devpriv->AdControlReg = AdControl_Int & 0xff; devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; @@ -486,7 +561,7 @@ static int pci9118_insn_read_ai(struct comedi_device *dev, * trigger stop */ - if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0, 0)) + if (!setup_channel_list(dev, s, 1, &insn->chanspec, 0, 0, 0, 0)) return -EINVAL; outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ @@ -494,20 +569,14 @@ static int pci9118_insn_read_ai(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + PCI9118_SOFTTRG); /* start conversion */ udelay(2); - timeout = 100; - while (timeout--) { - if (inl(dev->iobase + PCI9118_ADSTAT) & AdStatus_ADrdy) - goto conv_finish; - udelay(1); - } - comedi_error(dev, "A/D insn timeout"); - data[n] = 0; - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - return -ETIME; + ret = comedi_timeout(dev, s, insn, pci9118_ai_eoc, 0); + if (ret) { + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ + return ret; + } -conv_finish: - if (devpriv->ai16bits) { + if (s->maxdata == 0xffff) { data[n] = (inl(dev->iobase + PCI9118_AD_DATA) & 0xffff) ^ 0x8000; @@ -522,13 +591,11 @@ conv_finish: } -/* -============================================================================== -*/ 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); @@ -546,13 +613,11 @@ static int pci9118_insn_write_ao(struct comedi_device *dev, 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); @@ -562,40 +627,32 @@ static int pci9118_insn_read_ao(struct comedi_device *dev, 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 2; + return insn->n; } -/* -============================================================================== -*/ static int pci9118_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outl(s->state & 0x0f, dev->iobase + PCI9118_DO); - } + data[1] = s->state; - return 2; + return insn->n; } -/* -============================================================================== -*/ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev) { + struct pci9118_private *devpriv = dev->private; + devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM; outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); @@ -610,13 +667,15 @@ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev) static unsigned int defragment_dma_buffer(struct comedi_device *dev, struct comedi_subdevice *s, - short *dma_buffer, + unsigned short *dma_buffer, unsigned int num_samples) { + struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int i = 0, j = 0; unsigned int start_pos = devpriv->ai_add_front, - stop_pos = devpriv->ai_add_front + devpriv->ai_n_chan; - unsigned int raw_scanlen = devpriv->ai_add_front + devpriv->ai_n_chan + + stop_pos = devpriv->ai_add_front + cmd->chanlist_len; + unsigned int raw_scanlen = devpriv->ai_add_front + cmd->chanlist_len + devpriv->ai_add_back; for (i = 0; i < num_samples; i++) { @@ -631,21 +690,20 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev, return j; } -/* -============================================================================== -*/ static int move_block_from_dma(struct comedi_device *dev, struct comedi_subdevice *s, - short *dma_buffer, + unsigned short *dma_buffer, unsigned int num_samples) { + struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int num_bytes; num_samples = defragment_dma_buffer(dev, s, dma_buffer, num_samples); devpriv->ai_act_scan += - (s->async->cur_chan + num_samples) / devpriv->ai_n_scanlen; + (s->async->cur_chan + num_samples) / cmd->scan_end_arg; s->async->cur_chan += num_samples; - s->async->cur_chan %= devpriv->ai_n_scanlen; + s->async->cur_chan %= cmd->scan_end_arg; num_bytes = cfc_write_array_to_buffer(s, dma_buffer, num_samples * sizeof(short)); @@ -654,13 +712,157 @@ static int move_block_from_dma(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ +static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source) +{ + 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 (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; +} + +static void pci9118_calc_divisors(char mode, 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; + } + + *tim1 = *div1 * *div2 * I8254_OSC_BASE_4MHZ; + break; + } +} + +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); */ + 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); + } +} + +static int pci9118_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + 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_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 */ + + devpriv->ai_do = 0; + devpriv->usedma = 0; + + devpriv->ai_act_scan = 0; + devpriv->ai_act_dmapos = 0; + s->async->cur_chan = 0; + s->async->inttrig = NULL; + 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) { comedi_error(dev, "A/D FIFO Full status (Fatal Error!)"); devpriv->ai_maskerr &= ~0x100L; @@ -680,8 +882,7 @@ static char pci9118_decode_error_status(struct comedi_device *dev, } if (m & devpriv->ai_maskharderr) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return 1; } @@ -693,13 +894,14 @@ static void pci9118_ai_munge(struct comedi_device *dev, unsigned int num_bytes, unsigned int start_chan_index) { + struct pci9118_private *devpriv = dev->private; unsigned int i, num_samples = num_bytes / sizeof(short); - short *array = data; + unsigned short *array = data; for (i = 0; i < num_samples; i++) { if (devpriv->usedma) array[i] = be16_to_cpu(array[i]); - if (devpriv->ai16bits) + if (s->maxdata == 0xffff) array[i] ^= 0x8000; else array[i] = (array[i] >> 4) & 0x0fff; @@ -707,18 +909,15 @@ 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) { - register short sampl; - - s->async->events = 0; + 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)) @@ -727,63 +926,56 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, sampl = inw(dev->iobase + PCI9118_AD_DATA); #ifdef PCI9118_PARANOIDCHECK - if (devpriv->ai16bits == 0) { + if (s->maxdata != 0xffff) { if ((sampl & 0x000f) != devpriv->chanlist[s->async->cur_chan]) { /* data dropout! */ - printk - ("comedi: A/D SAMPL - data dropout: " - "received channel %d, expected %d!\n", - sampl & 0x000f, - devpriv->chanlist[s->async->cur_chan]); + 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; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } } #endif cfc_write_to_buffer(s, sampl); s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_scanlen) { + if (s->async->cur_chan >= cmd->scan_end_arg) { /* one scan done */ - s->async->cur_chan %= devpriv->ai_n_scanlen; + s->async->cur_chan %= cmd->scan_end_arg; devpriv->ai_act_scan++; - if (!(devpriv->ai_neverending)) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pci9118_ai_cancel(dev, s); + if (!devpriv->ai_neverending) { + /* all data sampled? */ + if (devpriv->ai_act_scan >= cmd->stop_arg) s->async->events |= COMEDI_CB_EOA; - } + } } - if (s->async->events) - comedi_event(dev, s); + cfc_handle_events(dev, s); } -/* -============================================================================== -*/ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short int_adstat, unsigned int int_amcc, unsigned short int_daq) { + struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int next_dma_buf, samplesinbuf, sampls, m; if (int_amcc & MASTER_ABORT_INT) { comedi_error(dev, "AMCC IRQ - MASTER DMA ABORT!"); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (int_amcc & TARGET_ABORT_INT) { comedi_error(dev, "AMCC IRQ - TARGET DMA ABORT!"); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - pci9118_ai_cancel(dev, s); - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (int_adstat & devpriv->ai_maskerr) @@ -793,7 +985,6 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1; /* number of received real samples */ -/* DPRINTK("dma_actbuf=%d\n",devpriv->dma_actbuf); */ if (devpriv->dma_doublebuf) { /* * switch DMA buffers if is used @@ -811,28 +1002,20 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, } if (samplesinbuf) { - m = devpriv->ai_data_len >> 1; /* - * how many samples is to - * end of buffer - */ -/* - * DPRINTK("samps=%d m=%d %d %d\n", - * samplesinbuf,m,s->async->buf_int_count,s->async->buf_int_ptr); - */ + /* how many samples is to end of buffer */ + m = s->async->prealloc_bufsz >> 1; sampls = m; move_block_from_dma(dev, s, devpriv->dmabuf_virt[devpriv->dma_actbuf], samplesinbuf); - m = m - sampls; /* m= how many samples was transferred */ + m = m - sampls; /* m=how many samples was transferred */ } -/* DPRINTK("YYY\n"); */ - if (!devpriv->ai_neverending) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pci9118_ai_cancel(dev, s); + if (!devpriv->ai_neverending) { + /* all data sampled? */ + if (devpriv->ai_act_scan >= cmd->stop_arg) s->async->events |= COMEDI_CB_EOA; - } + } if (devpriv->dma_doublebuf) { /* switch dma buffers */ devpriv->dma_actbuf = 1 - devpriv->dma_actbuf; @@ -845,92 +1028,74 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, interrupt_pci9118_ai_mode4_switch(dev); } - comedi_event(dev, s); + cfc_handle_events(dev, s); } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pci9118(int irq, void *d) +static irqreturn_t pci9118_interrupt(int irq, void *d) { struct comedi_device *dev = d; - unsigned int int_daq = 0, int_amcc, int_adstat; + struct comedi_subdevice *s = dev->read_subdev; + struct pci9118_private *devpriv = dev->private; + unsigned int intsrc; /* IRQ reasons from card */ + unsigned int intcsr; /* INT register from AMCC chip */ + unsigned int adstat; /* STATUS register */ if (!dev->attached) - return IRQ_NONE; /* not fully initialized */ + return IRQ_NONE; - int_daq = inl(dev->iobase + PCI9118_INTSRC) & 0xf; - /* get IRQ reasons from card */ - int_amcc = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* get INT register from AMCC chip */ + intsrc = inl(dev->iobase + PCI9118_INTSRC) & 0xf; + intcsr = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); -/* - * DPRINTK("INT daq=0x%01x amcc=0x%08x MWAR=0x%08x - * MWTC=0x%08x ADSTAT=0x%02x ai_do=%d\n", - * int_daq, int_amcc, inl(devpriv->iobase_a+AMCC_OP_REG_MWAR), - * inl(devpriv->iobase_a+AMCC_OP_REG_MWTC), - * inw(dev->iobase+PCI9118_ADSTAT)&0x1ff,devpriv->ai_do); - */ + if (!intsrc && !(intcsr & ANY_S593X_INT)) + return IRQ_NONE; - if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) - return IRQ_NONE; /* interrupt from other source */ - - outl(int_amcc | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* shutdown IRQ reasons in AMCC */ - - int_adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff; - /* get STATUS register */ - - if (devpriv->ai_do) { - if (devpriv->ai12_startstop) - if ((int_adstat & AdStatus_DTH) && - (int_daq & Int_DTrg)) { - /* start stop of measure */ - if (devpriv->ai12_startstop & START_AI_EXT) { - devpriv->ai12_startstop &= - ~START_AI_EXT; - if (!(devpriv->ai12_startstop & - STOP_AI_EXT)) - pci9118_exttrg_del - (dev, EXTTRG_AI); - /* deactivate EXT trigger */ - start_pacer(dev, devpriv->ai_do, - devpriv->ai_divisor1, - devpriv->ai_divisor2); - /* start pacer */ - outl(devpriv->AdControlReg, - dev->iobase + PCI9118_ADCNTRL); - } else { - if (devpriv->ai12_startstop & - STOP_AI_EXT) { - devpriv->ai12_startstop &= - ~STOP_AI_EXT; - pci9118_exttrg_del - (dev, EXTTRG_AI); - /* deactivate EXT trigger */ - devpriv->ai_neverending = 0; - /* - * well, on next interrupt from - * DMA/EOC measure will stop - */ - } - } - } + outl(intcsr | 0x00ff0000, devpriv->iobase_a + AMCC_OP_REG_INTCSR); + + adstat = inw(dev->iobase + PCI9118_ADSTAT) & 0x1ff; - (devpriv->int_ai_func) (dev, dev->subdevices + 0, int_adstat, - int_amcc, int_daq); + if (!devpriv->ai_do) + return IRQ_HANDLED; + if (devpriv->ai12_startstop) { + if ((adstat & AdStatus_DTH) && (intsrc & Int_DTrg)) { + /* start/stop of measure */ + if (devpriv->ai12_startstop & START_AI_EXT) { + /* deactivate EXT trigger */ + devpriv->ai12_startstop &= ~START_AI_EXT; + if (!(devpriv->ai12_startstop & STOP_AI_EXT)) + pci9118_exttrg_del(dev, EXTTRG_AI); + + /* start pacer */ + pci9118_start_pacer(dev, devpriv->ai_do); + outl(devpriv->AdControlReg, + dev->iobase + PCI9118_ADCNTRL); + } else if (devpriv->ai12_startstop & STOP_AI_EXT) { + /* deactivate EXT trigger */ + devpriv->ai12_startstop &= ~STOP_AI_EXT; + pci9118_exttrg_del(dev, EXTTRG_AI); + + /* on next interrupt measure will stop */ + devpriv->ai_neverending = 0; + } + } } + + if (devpriv->usedma) + interrupt_pci9118_ai_dma(dev, s, adstat, intcsr, intsrc); + else + interrupt_pci9118_ai_onesample(dev, s, adstat, intcsr, intsrc); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pci9118_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != devpriv->ai_inttrig_start) + 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; @@ -939,8 +1104,7 @@ static int pci9118_ai_inttrig(struct comedi_device *dev, outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); if (devpriv->ai_do != 3) { - start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, - devpriv->ai_divisor2); + pci9118_start_pacer(dev, devpriv->ai_do); devpriv->AdControlReg |= AdControl_SoftG; } outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); @@ -948,136 +1112,82 @@ static int pci9118_ai_inttrig(struct comedi_device *dev, return 1; } -/* -============================================================================== -*/ static int pci9118_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct boardtype *this_board = comedi_board(dev); + struct pci9118_private *devpriv = dev->private; int err = 0; - int tmp; + unsigned int flags; + unsigned int arg; unsigned int divisor1 = 0, divisor2 = 0; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_EXT | TRIG_INT); - tmp = cmd->scan_begin_src; + flags = TRIG_FOLLOW; if (devpriv->master) - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW; - else - cmd->scan_begin_src &= TRIG_FOLLOW; - - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + flags |= TRIG_TIMER | TRIG_EXT; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags); - tmp = cmd->convert_src; + flags = TRIG_TIMER | TRIG_EXT; if (devpriv->master) - cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW; - else - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; + flags |= TRIG_NOW; + err |= cfc_check_trigger_src(&cmd->convert_src, flags); - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE | TRIG_EXT; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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 2: - * make sure trigger sources are - * unique and mutually compatible - */ - - if (cmd->start_src != TRIG_NOW && - cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) { - cmd->start_src = TRIG_NOW; - err++; - } + /* Step 2a : make sure trigger sources are unique */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_INT && - cmd->scan_begin_src != TRIG_FOLLOW) { - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } + 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); - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) { - cmd->convert_src = TRIG_TIMER; - err++; - } + /* Step 2b : and mutually compatible */ - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } + if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) + err |= -EINVAL; - if (cmd->stop_src != TRIG_NONE && - cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_INT && cmd->stop_src != TRIG_EXT) { - cmd->stop_src = TRIG_COUNT; - err++; - } - - if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) { - cmd->start_src = TRIG_NOW; - err++; - } - - if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT) { - cmd->start_src = TRIG_NOW; - err++; - } + 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)))) { - cmd->convert_src = TRIG_TIMER; - err++; - } + (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW)))) + err |= -EINVAL; if ((cmd->scan_begin_src == TRIG_FOLLOW) && - (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT)))) { - cmd->convert_src = TRIG_TIMER; - err++; - } + (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT)))) + err |= -EINVAL; - if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) { - cmd->stop_src = TRIG_COUNT; - err++; - } + if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) + err |= -EINVAL; if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src & (TRIG_NOW | TRIG_EXT)) - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + 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)) - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + 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)) { @@ -1087,64 +1197,38 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, } if (cmd->scan_begin_src == TRIG_TIMER) - if (cmd->scan_begin_arg < this_board->ai_ns_min) { - cmd->scan_begin_arg = this_board->ai_ns_min; - err++; - } + 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++; - if (cmd->scan_end_arg > 65535) { - cmd->scan_end_arg = 65535; - err++; - } + err |= -EINVAL; + err |= cfc_check_trigger_arg_max(&cmd->scan_end_arg, + 65535); } if (cmd->convert_src & (TRIG_TIMER | TRIG_NOW)) - if (cmd->convert_arg < this_board->ai_ns_min) { - cmd->convert_arg = this_board->ai_ns_min; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + this_board->ai_ns_min); if (cmd->convert_src == TRIG_EXT) - if (cmd->convert_arg) { - cmd->convert_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); - if (cmd->chanlist_len > this_board->n_aichanlist) { - cmd->chanlist_len = this_board->n_aichanlist; - err++; - } - - if (cmd->scan_end_arg < cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + 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++; + err |= -EINVAL; } if (err) @@ -1153,50 +1237,30 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; -/* printk("S1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); -/* printk("S2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ - if (cmd->scan_begin_arg < this_board->ai_ns_min) - cmd->scan_begin_arg = this_board->ai_ns_min; - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->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)) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); -/* printk("s1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER - && cmd->convert_src == TRIG_NOW) { + arg = cmd->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) { - if (cmd->scan_begin_arg < - this_board->ai_ns_min * - (cmd->scan_end_arg + 2)) { - cmd->scan_begin_arg = - this_board->ai_ns_min * - (cmd->scan_end_arg + 2); -/* printk("s2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ - err++; - } + arg = this_board->ai_ns_min * + (cmd->scan_end_arg + 2); } else { - if (cmd->scan_begin_arg < - cmd->convert_arg * cmd->chanlist_len) { - cmd->scan_begin_arg = - cmd->convert_arg * - cmd->chanlist_len; -/* printk("s3 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ - err++; - } + arg = cmd->convert_arg * cmd->chanlist_len; } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -1211,56 +1275,40 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ -static int Compute_and_setup_dma(struct comedi_device *dev) +static int Compute_and_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { + struct pci9118_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned int dmalen0, dmalen1, i; - DPRINTK("adl_pci9118 EDBG: BGN: Compute_and_setup_dma()\n"); dmalen0 = devpriv->dmabuf_size[0]; dmalen1 = devpriv->dmabuf_size[1]; - DPRINTK("1 dmalen0=%d dmalen1=%d ai_data_len=%d\n", dmalen0, dmalen1, - devpriv->ai_data_len); /* isn't output buff smaller that our DMA buff? */ - if (dmalen0 > (devpriv->ai_data_len)) { - dmalen0 = devpriv->ai_data_len & ~3L; /* - * align to 32bit down - */ + if (dmalen0 > s->async->prealloc_bufsz) { + /* align to 32bit down */ + dmalen0 = s->async->prealloc_bufsz & ~3L; } - if (dmalen1 > (devpriv->ai_data_len)) { - dmalen1 = devpriv->ai_data_len & ~3L; /* - * align to 32bit down - */ + if (dmalen1 > s->async->prealloc_bufsz) { + /* align to 32bit down */ + dmalen1 = s->async->prealloc_bufsz & ~3L; } - DPRINTK("2 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); /* we want wake up every scan? */ if (devpriv->ai_flags & TRIG_WAKE_EOS) { if (dmalen0 < (devpriv->ai_n_realscanlen << 1)) { /* uff, too short DMA buffer, disable EOS support! */ devpriv->ai_flags &= (~TRIG_WAKE_EOS); - printk - ("comedi%d: WAR: DMA0 buf too short, can't " - "support TRIG_WAKE_EOS (%d<%d)\n", - dev->minor, dmalen0, - devpriv->ai_n_realscanlen << 1); + dev_info(dev->class_dev, + "WAR: DMA0 buf too short, can't support TRIG_WAKE_EOS (%d<%d)\n", + dmalen0, devpriv->ai_n_realscanlen << 1); } else { /* short first DMA buffer to one scan */ dmalen0 = devpriv->ai_n_realscanlen << 1; - DPRINTK - ("21 dmalen0=%d ai_n_realscanlen=%d " - "useeoshandle=%d\n", - dmalen0, devpriv->ai_n_realscanlen, - devpriv->useeoshandle); - if (devpriv->useeoshandle) - dmalen0 += 2; if (dmalen0 < 4) { - printk - ("comedi%d: ERR: DMA0 buf len bug? " - "(%d<4)\n", - dev->minor, dmalen0); + dev_info(dev->class_dev, + "ERR: DMA0 buf len bug? (%d<4)\n", + dmalen0); dmalen0 = 4; } } @@ -1269,32 +1317,21 @@ static int Compute_and_setup_dma(struct comedi_device *dev) if (dmalen1 < (devpriv->ai_n_realscanlen << 1)) { /* uff, too short DMA buffer, disable EOS support! */ devpriv->ai_flags &= (~TRIG_WAKE_EOS); - printk - ("comedi%d: WAR: DMA1 buf too short, " - "can't support TRIG_WAKE_EOS (%d<%d)\n", - dev->minor, dmalen1, - devpriv->ai_n_realscanlen << 1); + dev_info(dev->class_dev, + "WAR: DMA1 buf too short, can't support TRIG_WAKE_EOS (%d<%d)\n", + dmalen1, devpriv->ai_n_realscanlen << 1); } else { /* short second DMA buffer to one scan */ dmalen1 = devpriv->ai_n_realscanlen << 1; - DPRINTK - ("22 dmalen1=%d ai_n_realscanlen=%d " - "useeoshandle=%d\n", - dmalen1, devpriv->ai_n_realscanlen, - devpriv->useeoshandle); - if (devpriv->useeoshandle) - dmalen1 -= 2; if (dmalen1 < 4) { - printk - ("comedi%d: ERR: DMA1 buf len bug? " - "(%d<4)\n", - dev->minor, dmalen1); + dev_info(dev->class_dev, + "ERR: DMA1 buf len bug? (%d<4)\n", + dmalen1); dmalen1 = 4; } } } - DPRINTK("3 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); /* transfer without TRIG_WAKE_EOS */ if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) { /* if it's possible then align DMA buffers to length of scan */ @@ -1320,16 +1357,10 @@ static int Compute_and_setup_dma(struct comedi_device *dev) /* fits whole measure into one DMA buffer? */ if (dmalen0 > ((devpriv->ai_n_realscanlen << 1) * - devpriv->ai_scans)) { - DPRINTK - ("3.0 ai_n_realscanlen=%d ai_scans=%d\n", - devpriv->ai_n_realscanlen, - devpriv->ai_scans); + cmd->stop_arg)) { dmalen0 = (devpriv->ai_n_realscanlen << 1) * - devpriv->ai_scans; - DPRINTK("3.1 dmalen0=%d dmalen1=%d\n", dmalen0, - dmalen1); + cmd->stop_arg; dmalen0 &= ~3L; } else { /* * fits whole measure into @@ -1337,38 +1368,33 @@ static int Compute_and_setup_dma(struct comedi_device *dev) */ if (dmalen1 > ((devpriv->ai_n_realscanlen << 1) * - devpriv->ai_scans - dmalen0)) + cmd->stop_arg - dmalen0)) dmalen1 = (devpriv->ai_n_realscanlen << 1) * - devpriv->ai_scans - dmalen0; - DPRINTK("3.2 dmalen0=%d dmalen1=%d\n", dmalen0, - dmalen1); + cmd->stop_arg - dmalen0; dmalen1 &= ~3L; } } } - DPRINTK("4 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); - /* these DMA buffer size will be used */ devpriv->dma_actbuf = 0; devpriv->dmabuf_use_size[0] = dmalen0; devpriv->dmabuf_use_size[1] = dmalen1; - DPRINTK("5 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); #if 0 - if (devpriv->ai_n_scanlen < this_board->half_fifo_size) { + if (cmd->scan_end_arg < this_board->half_fifo_size) { devpriv->dmabuf_panic_size[0] = - (this_board->half_fifo_size / devpriv->ai_n_scanlen + - 1) * devpriv->ai_n_scanlen * sizeof(short); + (this_board->half_fifo_size / cmd->scan_end_arg + + 1) * cmd->scan_end_arg * sizeof(short); devpriv->dmabuf_panic_size[1] = - (this_board->half_fifo_size / devpriv->ai_n_scanlen + - 1) * devpriv->ai_n_scanlen * sizeof(short); + (this_board->half_fifo_size / cmd->scan_end_arg + + 1) * cmd->scan_end_arg * sizeof(short); } else { devpriv->dmabuf_panic_size[0] = - (devpriv->ai_n_scanlen << 1) % devpriv->dmabuf_size[0]; + (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[0]; devpriv->dmabuf_panic_size[1] = - (devpriv->ai_n_scanlen << 1) % devpriv->dmabuf_size[1]; + (cmd->scan_end_arg << 1) % devpriv->dmabuf_size[1]; } #endif @@ -1388,18 +1414,14 @@ static int Compute_and_setup_dma(struct comedi_device *dev) devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* allow bus mastering */ - DPRINTK("adl_pci9118 EDBG: END: Compute_and_setup_dma()\n"); return 0; } -/* -============================================================================== -*/ static int pci9118_ai_docmd_sampl(struct comedi_device *dev, struct comedi_subdevice *s) { - DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_sampl(%d,) [%d]\n", - dev->minor, devpriv->ai_do); + struct pci9118_private *devpriv = dev->private; + switch (devpriv->ai_do) { case 1: devpriv->AdControlReg |= AdControl_TmrTr; @@ -1419,9 +1441,6 @@ static int pci9118_ai_docmd_sampl(struct comedi_device *dev, return -EIO; } - devpriv->int_ai_func = interrupt_pci9118_ai_onesample; - /* transfer function */ - if (devpriv->ai12_startstop) pci9118_exttrg_add(dev, EXTTRG_AI); /* activate EXT trigger */ @@ -1439,26 +1458,22 @@ static int pci9118_ai_docmd_sampl(struct comedi_device *dev, outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); if (devpriv->ai_do != 3) { - start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, - devpriv->ai_divisor2); + pci9118_start_pacer(dev, devpriv->ai_do); devpriv->AdControlReg |= AdControl_SoftG; } outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); } - DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_docmd_sampl()\n"); return 0; } -/* -============================================================================== -*/ static int pci9118_ai_docmd_dma(struct comedi_device *dev, struct comedi_subdevice *s) { - DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma(%d,) [%d,%d]\n", - dev->minor, devpriv->ai_do, devpriv->usedma); - Compute_and_setup_dma(dev); + 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: @@ -1471,7 +1486,7 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev, devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg | AdFunction_BM | AdFunction_BS; - if (devpriv->usessh && (!devpriv->softsshdelay)) + if (cmd->convert_src == TRIG_NOW && !devpriv->softsshdelay) devpriv->AdFunctionReg |= AdFunction_BSSH; outl(devpriv->ai_n_realscanlen, dev->iobase + PCI9118_BURST); break; @@ -1503,9 +1518,6 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev, /* activate EXT trigger */ } - devpriv->int_ai_func = interrupt_pci9118_ai_dma; - /* transfer function */ - outl(0x02000000 | AINT_WRITE_COMPL, devpriv->iobase_a + AMCC_OP_REG_INTCSR); @@ -1513,36 +1525,25 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev, outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); if (devpriv->ai_do != 3) { - start_pacer(dev, devpriv->ai_do, devpriv->ai_divisor1, - devpriv->ai_divisor2); + pci9118_start_pacer(dev, devpriv->ai_do); devpriv->AdControlReg |= AdControl_SoftG; } outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); } - DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma()\n"); 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; - DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_cmd(%d,)\n", dev->minor); devpriv->ai12_startstop = 0; devpriv->ai_flags = cmd->flags; - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_n_scanlen = cmd->scan_end_arg; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_data = s->async->prealloc_buf; - devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; devpriv->ai_add_front = 0; devpriv->ai_add_back = 0; devpriv->ai_maskerr = 0x10e; @@ -1556,35 +1557,12 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } if (cmd->start_src == TRIG_INT) { devpriv->ai12_startstop |= START_AI_INT; - devpriv->ai_inttrig_start = cmd->start_arg; s->async->inttrig = pci9118_ai_inttrig; } -#if 0 - if (cmd->stop_src == TRIG_INT) { - devpriv->ai_neverending = 1; - devpriv->ai12_startstop |= STOP_AI_INT; - } -#endif if (cmd->stop_src == TRIG_NONE) devpriv->ai_neverending = 1; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; + if (cmd->stop_src == TRIG_COUNT) devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - } - - /* use sample&hold signal? */ - if (cmd->convert_src == TRIG_NOW) - devpriv->usessh = 1; - /* yes */ - else - devpriv->usessh = 0; - /* no */ - - DPRINTK("1 neverending=%d scans=%u usessh=%d ai_startstop=0x%2x\n", - devpriv->ai_neverending, devpriv->ai_scans, devpriv->usessh, - devpriv->ai12_startstop); /* * use additional sample at end of every scan @@ -1592,11 +1570,10 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) */ devpriv->ai_add_front = 0; devpriv->ai_add_back = 0; - devpriv->useeoshandle = 0; if (devpriv->master) { devpriv->usedma = 1; if ((cmd->flags & TRIG_WAKE_EOS) && - (devpriv->ai_n_scanlen == 1)) { + (cmd->scan_end_arg == 1)) { if (cmd->convert_src == TRIG_NOW) devpriv->ai_add_back = 1; if (cmd->convert_src == TRIG_TIMER) { @@ -1608,13 +1585,9 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } } if ((cmd->flags & TRIG_WAKE_EOS) && - (devpriv->ai_n_scanlen & 1) && - (devpriv->ai_n_scanlen > 1)) { + (cmd->scan_end_arg & 1) && + (cmd->scan_end_arg > 1)) { if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* - * vpriv->useeoshandle=1; // change DMA transfer - * block to fit EOS on every second call - */ devpriv->usedma = 0; /* * XXX maybe can be corrected to use 16 bit DMA @@ -1634,7 +1607,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * we need software S&H signal? * It adds two samples before every scan as minimum */ - if (devpriv->usessh && devpriv->softsshdelay) { + if (cmd->convert_src == TRIG_NOW && devpriv->softsshdelay) { devpriv->ai_add_front = 2; if ((devpriv->usedma == 1) && (devpriv->ai_add_back == 1)) { /* move it to front */ @@ -1651,7 +1624,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_add_front = addchans + 1; if (devpriv->usedma == 1) if ((devpriv->ai_add_front + - devpriv->ai_n_chan + + cmd->chanlist_len + devpriv->ai_add_back) & 1) devpriv->ai_add_front++; /* round up to 32 bit */ @@ -1660,27 +1633,20 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* well, we now know what must be all added */ devpriv->ai_n_realscanlen = /* * what we must take from card in real - * to have ai_n_scanlen on output? + * to have cmd->scan_end_arg on output? */ - (devpriv->ai_add_front + devpriv->ai_n_chan + - devpriv->ai_add_back) * (devpriv->ai_n_scanlen / - devpriv->ai_n_chan); - - DPRINTK("2 usedma=%d realscan=%d af=%u n_chan=%d ab=%d n_scanlen=%d\n", - devpriv->usedma, - devpriv->ai_n_realscanlen, devpriv->ai_add_front, - devpriv->ai_n_chan, devpriv->ai_add_back, - devpriv->ai_n_scanlen); + (devpriv->ai_add_front + cmd->chanlist_len + + devpriv->ai_add_back) * (cmd->scan_end_arg / + cmd->chanlist_len); /* check and setup channel list */ - if (!check_channel_list(dev, s, devpriv->ai_n_chan, - devpriv->ai_chanlist, devpriv->ai_add_front, + if (!check_channel_list(dev, s, cmd->chanlist_len, + cmd->chanlist, devpriv->ai_add_front, devpriv->ai_add_back)) return -EINVAL; - if (!setup_channel_list(dev, s, devpriv->ai_n_chan, - devpriv->ai_chanlist, 0, devpriv->ai_add_front, - devpriv->ai_add_back, devpriv->usedma, - devpriv->useeoshandle)) + if (!setup_channel_list(dev, s, cmd->chanlist_len, + cmd->chanlist, 0, devpriv->ai_add_front, + devpriv->ai_add_back, devpriv->usedma)) return -EINVAL; /* compute timers settings */ @@ -1702,9 +1668,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_flags, devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, - &devpriv->ai_divisor2, devpriv->usessh, + &devpriv->ai_divisor2, devpriv->ai_add_front); - devpriv->ai_timer2 = cmd->convert_arg; } if ((cmd->scan_begin_src == TRIG_TIMER) && @@ -1724,10 +1689,8 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_flags, devpriv->ai_n_realscanlen, &devpriv->ai_divisor1, - &devpriv->ai_divisor2, devpriv->usessh, + &devpriv->ai_divisor2, devpriv->ai_add_front); - devpriv->ai_timer1 = cmd->scan_begin_arg; - devpriv->ai_timer2 = cmd->convert_arg; } if ((cmd->scan_begin_src == TRIG_FOLLOW) @@ -1735,7 +1698,7 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_do = 3; } - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pci9118_start_pacer(dev, -1); /* stop pacer */ devpriv->AdControlReg = 0; /* * bipolar, S.E., use 8254, stop 8354, @@ -1761,378 +1724,19 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_act_scan = 0; devpriv->ai_act_dmapos = 0; s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; if (devpriv->usedma) ret = pci9118_ai_docmd_dma(dev, s); else ret = pci9118_ai_docmd_sampl(dev, s); - DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_cmd()\n"); return ret; } -/* -============================================================================== -*/ -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, int n_chan, - unsigned int *chanlist, int frontadd, int backadd) -{ - unsigned int i, differencial = 0, bipolar = 0; - - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - comedi_error(dev, "range/channel list is empty!"); - return 0; - } - if ((frontadd + n_chan + backadd) > s->len_chanlist) { - printk - ("comedi%d: range/channel list is too long for " - "actual configuration (%d>%d)!", - dev->minor, n_chan, s->len_chanlist - frontadd - backadd); - return 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 */ - if (n_chan > 1) - for (i = 1; i < n_chan; i++) { /* check S.E/diff */ - if ((CR_AREF(chanlist[i]) == AREF_DIFF) != - (differencial)) { - comedi_error(dev, - "Differencial and single ended " - "inputs can't be mixtured!"); - return 0; - } - if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) != - (bipolar)) { - comedi_error(dev, - "Bipolar and unipolar ranges " - "can't be mixtured!"); - return 0; - } - if ((!devpriv->usemux) & (differencial) & - (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) { - comedi_error(dev, - "If AREF_DIFF is used then is " - "available only first 8 channels!"); - return 0; - } - } - - 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, char useeos) -{ - unsigned int i, differencial = 0, bipolar = 0; - unsigned int scanquad, gain, ssh = 0x00; - - DPRINTK - ("adl_pci9118 EDBG: BGN: setup_channel_list" - "(%d,.,%d,.,%d,%d,%d,%d)\n", - dev->minor, n_chan, rot, frontadd, backadd, usedma); - - 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 */ - - 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 */ - ssh = devpriv->softsshsample; - DPRINTK("FA: %04x: ", ssh); - 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); - DPRINTK("%02x ", scanquad | ssh); - ssh = devpriv->softsshhold; - } - DPRINTK("\n "); - } - - DPRINTK("SL: ", ssh); - 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); - DPRINTK("%02x ", scanquad | ssh); - } - DPRINTK("\n "); - - if (backadd) { /* insert channels for fit onto 32bit DMA */ - DPRINTK("BA: %04x: ", ssh); - 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); - DPRINTK("%02x ", scanquad | ssh); - } - DPRINTK("\n "); - } -#ifdef PCI9118_PARANOIDCHECK - devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma]; - /* for 32bit operations */ - if (useeos) { - for (i = 1; i < n_chan; i++) { /* store range list to card */ - devpriv->chanlist[(n_chan + i) ^ usedma] = - (CR_CHAN(chanlist[i]) & 0xf) << rot; - } - devpriv->chanlist[(2 * n_chan) ^ usedma] = - devpriv->chanlist[0 ^ usedma]; - /* for 32bit operations */ - useeos = 2; - } else { - useeos = 1; - } -#ifdef PCI9118_EXTDEBUG - DPRINTK("CHL: "); - for (i = 0; i <= (useeos * n_chan); i++) - DPRINTK("%04x ", devpriv->chanlist[i]); - - DPRINTK("\n "); -#endif -#endif - outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */ - /* udelay(100); important delay, or first sample will be crippled */ - - DPRINTK("adl_pci9118 EDBG: END: setup_channel_list()\n"); - return 1; /* we can serve this with scan logic */ -} - -/* -============================================================================== - calculate 8254 divisors if they are used for dual timing -*/ -static void pci9118_calc_divisors(char mode, 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, - char usessh, unsigned int chnsshfront) -{ - DPRINTK - ("adl_pci9118 EDBG: BGN: pci9118_calc_divisors" - "(%d,%d,.,%u,%u,%u,%d,.,.,,%u,%u)\n", - mode, dev->minor, *tim1, *tim2, flags, chans, usessh, chnsshfront); - switch (mode) { - case 1: - case 4: - if (*tim2 < this_board->ai_ns_min) - *tim2 = this_board->ai_ns_min; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, div1, div2, - tim2, flags & TRIG_ROUND_NEAREST); - DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u\n", - devpriv->i8254_osc_base, *div1, *div2, *tim1); - break; - case 2: - if (*tim2 < this_board->ai_ns_min) - *tim2 = this_board->ai_ns_min; - DPRINTK("1 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - *div1 = *tim2 / devpriv->i8254_osc_base; - /* convert timer (burst) */ - DPRINTK("2 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - if (*div1 < this_board->ai_pacer_min) - *div1 = this_board->ai_pacer_min; - DPRINTK("3 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - *div2 = *tim1 / devpriv->i8254_osc_base; /* scan timer */ - DPRINTK("4 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - *div2 = *div2 / *div1; /* major timer is c1*c2 */ - DPRINTK("5 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - if (*div2 < chans) - *div2 = chans; - DPRINTK("6 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - - *tim2 = *div1 * devpriv->i8254_osc_base; - /* real convert timer */ - - if (usessh & (chnsshfront == 0)) /* use BSSH signal */ - if (*div2 < (chans + 2)) - *div2 = chans + 2; - - DPRINTK("7 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - *tim1 = *div1 * *div2 * devpriv->i8254_osc_base; - DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u timer2=%u\n", - devpriv->i8254_osc_base, *div1, *div2, *tim1, *tim2); - break; - } - DPRINTK("adl_pci9118 EDBG: END: pci9118_calc_divisors(%u,%u)\n", - *div1, *div2); -} - -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) -{ - outl(0x74, dev->iobase + PCI9118_CNTCTRL); - outl(0xb4, dev->iobase + PCI9118_CNTCTRL); -/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */ - 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); - } -} - -/* -============================================================================== -*/ -static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source) -{ - 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) -{ - 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; -} - -/* -============================================================================== -*/ -static int pci9118_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - 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); - start_pacer(dev, 0, 0, 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 */ - - devpriv->ai_do = 0; - devpriv->usedma = 0; - - devpriv->ai_act_scan = 0; - devpriv->ai_act_dmapos = 0; - s->async->cur_chan = 0; - s->async->inttrig = NULL; - devpriv->ai_buf_ptr = 0; - devpriv->ai_neverending = 0; - devpriv->dma_actbuf = 0; - - 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 int pci9118_reset(struct comedi_device *dev) { + struct pci9118_private *devpriv = dev->private; + devpriv->IntControlReg = 0; devpriv->exttrg_users = 0; inl(dev->iobase + PCI9118_INTCTRL); @@ -2140,7 +1744,7 @@ static int pci9118_reset(struct comedi_device *dev) /* disable interrupts source */ outl(0x30, dev->iobase + PCI9118_CNTCTRL); /* outl(0xb4, dev->iobase + PCI9118_CNTCTRL); */ - start_pacer(dev, 0, 0, 0); /* stop 8254 counters */ + pci9118_start_pacer(dev, 0); /* stop 8254 counters */ devpriv->AdControlReg = 0; outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); /* @@ -2183,190 +1787,141 @@ static int pci9118_reset(struct comedi_device *dev) * disable INT and DMA */ - devpriv->cnt0_users = 0; devpriv->exttrg_users = 0; return 0; } /* -============================================================================== -*/ -static int pci9118_attach(struct comedi_device *dev, - struct comedi_devconfig *it) + * 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) { - struct comedi_subdevice *s; - int ret, pages, i; - unsigned short master; - unsigned int irq; - unsigned long iobase_a, iobase_9; - struct pci_dev *pcidev; - int opt_bus, opt_slot; - const char *errstr; - unsigned char pci_bus, pci_slot, pci_func; - u16 u16w; - - printk("comedi%d: adl_pci9118: board=%s", dev->minor, this_board->name); + unsigned int i; - opt_bus = it->options[0]; - opt_slot = it->options[1]; - if (it->options[3] & 1) - master = 0; /* user don't want use bus master */ - else - master = 1; + for (i = 0; i < ARRAY_SIZE(boardtypes); i++) + if (pcidev->device == boardtypes[i].device_id) + return &boardtypes[i]; + return NULL; +} - ret = alloc_private(dev, sizeof(struct pci9118_private)); - if (ret < 0) { - printk(" - Allocation failed!\n"); - return -ENOMEM; - } +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]; - /* Look for matching PCI device */ - errstr = "not found!"; - pcidev = NULL; - while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_AMCC, - this_board->device_id, - pcidev))) { - /* Found matching vendor/device. */ - if (opt_bus || opt_slot) { - /* Check bus/slot. */ - if (opt_bus != pcidev->bus->number - || opt_slot != PCI_SLOT(pcidev->devfn)) - continue; /* no match */ - } - /* - * Look for device that isn't in use. - * Enable PCI device and request regions. - */ - if (comedi_pci_enable(pcidev, "adl_pci9118")) { - errstr = - "failed to enable PCI device and request regions!"; + for_each_pci_dev(pcidev) { + if (pcidev->vendor != PCI_VENDOR_ID_AMCC) + continue; + if (pcidev->device != this_board->device_id) continue; + if (bus || slot) { + /* requested particular bus/slot */ + if (pcidev->bus->number != bus || + PCI_SLOT(pcidev->devfn) != slot) + continue; } - break; + return pcidev; } + dev_err(dev->class_dev, + "no supported board found! (req. bus/slot : %d/%d)\n", + bus, slot); + return NULL; +} - if (!pcidev) { - if (opt_bus || opt_slot) { - printk(KERN_ERR " - Card at b:s %d:%d %s\n", - opt_bus, opt_slot, errstr); - } else { - printk(KERN_ERR " - Card %s\n", errstr); - } - return -EIO; - } +static int pci9118_common_attach(struct comedi_device *dev, int disable_irq, + int master, int ext_mux, int softsshdelay, + int hw_err_mask) +{ + const struct boardtype *this_board = comedi_board(dev); + struct pci9118_private *devpriv = dev->private; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + int ret, pages, i; + u16 u16w; + dev->board_name = this_board->name; + ret = comedi_pci_enable(dev); + if (ret) + return ret; if (master) pci_set_master(pcidev); - - pci_bus = pcidev->bus->number; - pci_slot = PCI_SLOT(pcidev->devfn); - pci_func = PCI_FUNC(pcidev->devfn); - irq = pcidev->irq; - iobase_a = pci_resource_start(pcidev, 0); - iobase_9 = pci_resource_start(pcidev, 2); - - printk(KERN_ERR ", b:s:f=%d:%d:%d, io=0x%4lx, 0x%4lx", pci_bus, - pci_slot, pci_func, iobase_9, iobase_a); - - dev->iobase = iobase_9; - dev->board_name = this_board->name; - - devpriv->pcidev = pcidev; - devpriv->iobase_a = iobase_a; + devpriv->iobase_a = pci_resource_start(pcidev, 0); + dev->iobase = pci_resource_start(pcidev, 2); pci9118_reset(dev); - if (it->options[3] & 2) - irq = 0; /* user don't want use IRQ */ - if (irq > 0) { - if (request_irq(irq, interrupt_pci9118, IRQF_SHARED, - "ADLink PCI-9118", dev)) { - printk(", unable to allocate IRQ %d, DISABLING IT", - irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(", irq=%u", irq); - } - } else { - printk(", IRQ disabled"); - } - - dev->irq = irq; - 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] = - (short *)__get_free_pages(GFP_KERNEL, - pages); + (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_samples[i] = - devpriv->dmabuf_size[i] >> 1; devpriv->dmabuf_hw[i] = virt_to_bus((void *) devpriv->dmabuf_virt[i]); } } if (!devpriv->dmabuf_virt[0]) { - printk(", Can't allocate DMA buffer, DMA disabled!"); + dev_warn(dev->class_dev, + "Can't allocate DMA buffer, DMA disabled!\n"); master = 0; } - if (devpriv->dmabuf_virt[1]) devpriv->dma_doublebuf = 1; - } - devpriv->master = master; - if (devpriv->master) - printk(", bus master"); - else - printk(", no bus master"); - - devpriv->usemux = 0; - if (it->options[2] > 0) { - devpriv->usemux = it->options[2]; - if (devpriv->usemux > 256) - devpriv->usemux = 256; /* max 256 channels! */ - if (it->options[4] > 0) - if (devpriv->usemux > 128) { - devpriv->usemux = 128; - /* max 128 channels with softare S&H! */ - } - printk(", ext. mux %d channels", devpriv->usemux); + + if (ext_mux > 0) { + if (ext_mux > 256) + ext_mux = 256; /* max 256 channels! */ + if (softsshdelay > 0) + if (ext_mux > 128) + ext_mux = 128; + devpriv->usemux = ext_mux; + } else { + devpriv->usemux = 0; } - devpriv->softsshdelay = it->options[4]; - if (devpriv->softsshdelay < 0) { - /* select sample&hold signal polarity */ - devpriv->softsshdelay = -devpriv->softsshdelay; + if (softsshdelay < 0) { + /* select sample&hold signal polarity */ + devpriv->softsshdelay = -softsshdelay; devpriv->softsshsample = 0x80; devpriv->softsshhold = 0x00; } else { + devpriv->softsshdelay = softsshdelay; devpriv->softsshsample = 0x00; devpriv->softsshhold = 0x80; } - printk(".\n"); - - pci_read_config_word(devpriv->pcidev, PCI_COMMAND, &u16w); - pci_write_config_word(devpriv->pcidev, PCI_COMMAND, u16w | 64); + pci_read_config_word(pcidev, PCI_COMMAND, &u16w); + pci_write_config_word(pcidev, PCI_COMMAND, u16w | 64); /* Enable parity check for parity error */ - ret = alloc_subdevices(dev, 4); - if (ret < 0) + if (!disable_irq && pcidev->irq) { + ret = request_irq(pcidev->irq, pci9118_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - s = dev->subdevices + 0; - dev->read_subdev = s; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; if (devpriv->usemux) @@ -2375,18 +1930,19 @@ static int pci9118_attach(struct comedi_device *dev, s->n_chan = this_board->n_aichan; s->maxdata = this_board->ai_maxdata; - s->len_chanlist = this_board->n_aichanlist; s->range_table = this_board->rangelist_ai; - s->cancel = pci9118_ai_cancel; s->insn_read = pci9118_insn_read_ai; if (dev->irq) { + dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = this_board->n_aichanlist; s->do_cmdtest = pci9118_ai_cmdtest; s->do_cmd = pci9118_ai_cmd; + s->cancel = pci9118_ai_cancel; s->munge = pci9118_ai_munge; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->n_aochan; @@ -2396,60 +1952,95 @@ static int pci9118_attach(struct comedi_device *dev, s->insn_write = pci9118_insn_write_ao; s->insn_read = pci9118_insn_read_ao; - s = dev->subdevices + 2; + 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->io_bits = 0; /* all bits input */ s->insn_bits = pci9118_insn_bits_di; - s = dev->subdevices + 3; + 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->io_bits = 0xf; /* all bits output */ s->insn_bits = pci9118_insn_bits_do; - devpriv->valid = 1; - devpriv->i8254_osc_base = 250; /* 250ns=4MHz */ devpriv->ai_maskharderr = 0x10a; /* default measure crash condition */ - if (it->options[5]) /* disable some requested */ - devpriv->ai_maskharderr &= ~it->options[5]; + if (hw_err_mask) /* disable some requested */ + devpriv->ai_maskharderr &= ~hw_err_mask; - switch (this_board->ai_maxdata) { - case 0xffff: - devpriv->ai16bits = 1; - break; - default: - devpriv->ai16bits = 0; - break; - } return 0; } -/* -============================================================================== -*/ -static int pci9118_detach(struct comedi_device *dev) +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; + + 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); +} + +static int pci9118_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - if (dev->private) { - if (devpriv->valid) + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct pci9118_private *devpriv; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + 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); +} + +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->pcidev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pcidev); - - pci_dev_put(devpriv->pcidev); - } if (devpriv->dmabuf_virt[0]) free_pages((unsigned long)devpriv->dmabuf_virt[0], devpriv->dmabuf_pages[0]); @@ -2457,13 +2048,42 @@ static int pci9118_detach(struct comedi_device *dev) free_pages((unsigned long)devpriv->dmabuf_virt[1], devpriv->dmabuf_pages[1]); } + comedi_pci_disable(dev); + if (pcidev) + pci_dev_put(pcidev); +} - return 0; +static struct comedi_driver adl_pci9118_driver = { + .driver_name = "adl_pci9118", + .module = THIS_MODULE, + .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), +}; + +static int adl_pci9118_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &adl_pci9118_driver, + id->driver_data); } -/* -============================================================================== -*/ +static const struct pci_device_id adl_pci9118_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMCC, 0x80d9) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adl_pci9118_pci_table); + +static struct pci_driver adl_pci9118_pci_driver = { + .name = "adl_pci9118", + .id_table = adl_pci9118_pci_table, + .probe = adl_pci9118_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adl_pci9118_driver, adl_pci9118_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index 5361f318b01..b4ea37704ea 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: adq12b @@ -78,6 +73,9 @@ If you do not specify any options, they will default to */ +#include <linux/module.h> +#include <linux/delay.h> + #include "../comedidev.h" /* address scheme (page 2.17 of the manual) */ @@ -96,237 +94,54 @@ If you do not specify any options, they will default to /* mask of the bit at STINR to check end of conversion */ #define ADQ12B_EOC 0x20 -#define TIMEOUT 20 - /* available ranges through the PGA gains */ -static const struct comedi_lrange range_adq12b_ai_bipolar = { 4, { - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - BIP_RANGE(0.5) - } -}; - -static const struct comedi_lrange range_adq12b_ai_unipolar = { 4, { - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1), - UNI_RANGE - (0.5) - } -}; - -struct adq12b_board { - const char *name; - int ai_se_chans; - int ai_diff_chans; - int ai_bits; - int di_chans; - int do_chans; +static const struct comedi_lrange range_adq12b_ai_bipolar = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5) + } }; -static const struct adq12b_board adq12b_boards[] = { - { - .name = "adq12b", - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 12, - .di_chans = 5, - .do_chans = 8} -/* potentially, more adq-based deviced will be added */ -/*, - .name = "adq12b", - .ai_chans = 16, // this is just for reference, hardcoded again later - .ai_bits = 12, - .di_chans = 8, - .do_chans = 5 - }*/ +static const struct comedi_lrange range_adq12b_ai_unipolar = { + 4, { + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5) + } }; -#define thisboard ((const struct adq12b_board *)dev->board_ptr) - struct adq12b_private { int unipolar; /* option 2 of comedi_config (1 is iobase) */ int differential; /* option 3 of comedi_config */ int last_channel; int last_range; - unsigned int digital_state; -}; - -#define devpriv ((struct adq12b_private *)dev->private) - -/* - * 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 int adq12b_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int adq12b_detach(struct comedi_device *dev); - -static struct comedi_driver driver_adq12b = { - .driver_name = "adq12b", - .module = THIS_MODULE, - .attach = adq12b_attach, - .detach = adq12b_detach, - .board_name = &adq12b_boards[0].name, - .offset = sizeof(struct adq12b_board), - .num_names = ARRAY_SIZE(adq12b_boards), }; -static int adq12b_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int adq12b_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int adq12b_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase; - int unipolar, differential; - - iobase = it->options[0]; - unipolar = it->options[1]; - differential = it->options[2]; - - printk(KERN_INFO "comedi%d: adq12b called with options base=0x%03lx, " - "%s and %s\n", dev->minor, iobase, - (unipolar == 1) ? "unipolar" : "bipolar", - (differential == 1) ? "differential" : "single-ended"); - - /* if no address was specified, try the default 0x300 */ - if (iobase == 0) { - printk(KERN_WARNING "comedi%d: adq12b warning: I/O base " - "address not specified. Trying the default 0x300.\n", - dev->minor); - iobase = 0x300; - } - - printk("comedi%d: adq12b: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, ADQ12B_SIZE, "adq12b")) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct adq12b_private)) < 0) - return -ENOMEM; - -/* fill in devpriv structure */ - devpriv->unipolar = unipolar; - devpriv->differential = differential; - devpriv->digital_state = 0; -/* initialize channel and range to -1 so we make sure we always write - at least once to the CTREG in the instruction */ - devpriv->last_channel = -1; - devpriv->last_range = -1; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - if (differential) { - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = thisboard->ai_diff_chans; - } else { - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = thisboard->ai_se_chans; - } - - if (unipolar) - s->range_table = &range_adq12b_ai_unipolar; - else - s->range_table = &range_adq12b_ai_bipolar; - - s->maxdata = (1 << thisboard->ai_bits) - 1; - - s->len_chanlist = 4; /* This is the maximum chanlist length that - the board can handle */ - s->insn_read = adq12b_ai_rinsn; - - s = dev->subdevices + 1; - /* digital input subdevice */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = thisboard->di_chans; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = adq12b_di_insn_bits; - - s = dev->subdevices + 2; - /* digital output subdevice */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->do_chans; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = adq12b_do_insn_bits; - - printk(KERN_INFO "attached\n"); - - return 0; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int adq12b_detach(struct comedi_device *dev) +static int adq12b_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - if (dev->iobase) - release_region(dev->iobase, ADQ12B_SIZE); + unsigned char status; - kfree(devpriv); - - printk(KERN_INFO "comedi%d: adq12b: removed\n", dev->minor); - - return 0; + status = inb(dev->iobase + ADQ12B_STINR); + if (status & ADQ12B_EOC) + return 0; + return -EBUSY; } -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ - static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + struct adq12b_private *devpriv = dev->private; + int n; int range, channel; unsigned char hi, lo, status; + int ret; /* change channel and range only if it is different from the previous */ range = CR_RANGE(insn->chanspec); @@ -343,20 +158,14 @@ static int adq12b_ai_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* wait for end of conversion */ - i = 0; - do { - /* udelay(1); */ - status = inb(dev->iobase + ADQ12B_STINR); - status = status & ADQ12B_EOC; - } while (status == 0 && ++i < TIMEOUT); - /* } while (++i < 10); */ + ret = comedi_timeout(dev, s, insn, adq12b_ai_eoc, 0); + if (ret) + return ret; /* read data */ hi = inb(dev->iobase + ADQ12B_ADHIG); lo = inb(dev->iobase + ADQ12B_ADLOW); - /* printk("debug: chan=%d range=%d status=%d hi=%d lo=%d\n", - channel, range, status, hi, lo); */ data[n] = (hi << 8) | lo; } @@ -373,47 +182,111 @@ static int adq12b_di_insn_bits(struct comedi_device *dev, /* only bits 0-4 have information about digital inputs */ data[1] = (inb(dev->iobase + ADQ12B_STINR) & (0x1f)); - return 2; + return insn->n; } static int adq12b_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int channel; - - for (channel = 0; channel < 8; channel++) - if (((data[0] >> channel) & 0x01) != 0) - outb((((data[1] >> channel) & 0x01) << 3) | channel, - dev->iobase + ADQ12B_OUTBR); - - /* store information to retrieve when asked for reading */ - if (data[0]) { - devpriv->digital_state &= ~data[0]; - devpriv->digital_state |= (data[0] & data[1]); + unsigned int mask; + unsigned int chan; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + for (chan = 0; chan < 8; chan++) { + if ((mask >> chan) & 0x01) { + val = (s->state >> chan) & 0x01; + outb((val << 3) | chan, + dev->iobase + ADQ12B_OUTBR); + } + } } - data[1] = devpriv->digital_state; + data[1] = s->state; - return 2; + return insn->n; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_adq12b_init_module(void) +static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - return comedi_driver_register(&driver_adq12b); -} + struct adq12b_private *devpriv; + struct comedi_subdevice *s; + int ret; -static void __exit driver_adq12b_cleanup_module(void) -{ - comedi_driver_unregister(&driver_adq12b); + ret = comedi_request_region(dev, it->options[0], ADQ12B_SIZE); + if (ret) + return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + devpriv->unipolar = it->options[1]; + devpriv->differential = it->options[2]; + /* + * initialize channel and range to -1 so we make sure we + * always write at least once to the CTREG in the instruction + */ + devpriv->last_channel = -1; + devpriv->last_range = -1; + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + s = &dev->subdevices[0]; + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + if (devpriv->differential) { + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 8; + } else { + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + } + + if (devpriv->unipolar) + s->range_table = &range_adq12b_ai_unipolar; + else + s->range_table = &range_adq12b_ai_bipolar; + + s->maxdata = 0xfff; + + s->len_chanlist = 4; /* This is the maximum chanlist length that + the board can handle */ + s->insn_read = adq12b_ai_rinsn; + + s = &dev->subdevices[1]; + /* digital input subdevice */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 5; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = adq12b_di_insn_bits; + + s = &dev->subdevices[2]; + /* digital output subdevice */ + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = adq12b_do_insn_bits; + + return 0; } -module_init(driver_adq12b_init_module); -module_exit(driver_adq12b_cleanup_module); +static struct comedi_driver adq12b_driver = { + .driver_name = "adq12b", + .module = THIS_MODULE, + .attach = adq12b_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(adq12b_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index da2b75b15d4..602b7a1e40e 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -41,40 +41,21 @@ Configuration options: device will be used. */ +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include "comedi_pci.h" - +#include "comedi_fc.h" #include "8253.h" #include "amcc_s5933.h" -#define PCI171x_PARANOIDCHECK /* if defined, then is used code which control - * correct channel number on every 12 bit - * sample */ - -#undef PCI171X_EXTDEBUG - -#define DRV_NAME "adv_pci1710" - -#undef DPRINTK -#ifdef PCI171X_EXTDEBUG -#define DPRINTK(fmt, args...) printk(fmt, ## args) -#else -#define DPRINTK(fmt, args...) -#endif - -#define PCI_VENDOR_ID_ADVANTECH 0x13fe - /* hardware types of the cards */ #define TYPE_PCI171X 0 #define TYPE_PCI1713 2 #define TYPE_PCI1720 3 -#define IORANGE_171x 32 -#define IORANGE_1720 16 - #define PCI171x_AD_DATA 0 /* R: A/D data */ #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */ #define PCI171x_RANGE 2 /* W: A/D gain/range register */ @@ -88,6 +69,9 @@ Configuration options: #define PCI171x_DAREF 14 /* W: D/A reference control */ #define PCI171x_DI 16 /* R: digi inputs */ #define PCI171x_DO 16 /* R: digi inputs */ + +#define PCI171X_TIMER_BASE 0x18 + #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */ #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */ #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */ @@ -130,75 +114,83 @@ Configuration options: /* D/A synchronized control (PCI1720_SYNCONT) */ #define Syncont_SC0 1 /* set synchronous output mode */ -static const struct comedi_lrange range_pci1710_3 = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(10), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } +static const struct comedi_lrange range_pci1710_3 = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(10), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x10, 0x11, 0x12, 0x13 }; -static const struct comedi_lrange range_pci1710hg = { 12, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01) - } +static const struct comedi_lrange range_pci1710hg = { + 12, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x10, 0x11, 0x12, 0x13 }; -static const struct comedi_lrange range_pci17x1 = { 5, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625) - } +static const struct comedi_lrange range_pci17x1 = { + 5, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 }; -static const struct comedi_lrange range_pci1720 = { 4, { - UNI_RANGE(5), - UNI_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(10) - } +static const struct comedi_lrange range_pci1720 = { + 4, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10) + } }; -static const struct comedi_lrange range_pci171x_da = { 2, { - UNI_RANGE(5), - UNI_RANGE(10), - } +static const struct comedi_lrange range_pci171x_da = { + 2, { + UNI_RANGE(5), + UNI_RANGE(10) + } }; -static int pci1710_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci1710_detach(struct comedi_device *dev); +enum pci1710_boardid { + BOARD_PCI1710, + BOARD_PCI1710HG, + BOARD_PCI1711, + BOARD_PCI1713, + BOARD_PCI1720, + BOARD_PCI1731, +}; struct boardtype { const char *name; /* board name */ - int device_id; - int iorange; /* I/O range len */ char have_irq; /* 1=card support IRQ */ char cardtype; /* 0=1710& co. 2=1713, ... */ int n_aichan; /* num of A/D chans */ @@ -216,118 +208,112 @@ struct boardtype { unsigned int fifo_half_size; /* size of FIFO/2 */ }; -static DEFINE_PCI_DEVICE_TABLE(pci1710_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1710) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1711) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1713) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1720) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1731) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci1710_pci_table); - static const struct boardtype boardtypes[] = { - {"pci1710", 0x1710, - IORANGE_171x, 1, TYPE_PCI171X, - 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff, - &range_pci1710_3, range_codes_pci1710_3, - &range_pci171x_da, - 10000, 2048}, - {"pci1710hg", 0x1710, - IORANGE_171x, 1, TYPE_PCI171X, - 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff, - &range_pci1710hg, range_codes_pci1710hg, - &range_pci171x_da, - 10000, 2048}, - {"pci1711", 0x1711, - IORANGE_171x, 1, TYPE_PCI171X, - 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff, - &range_pci17x1, range_codes_pci17x1, &range_pci171x_da, - 10000, 512}, - {"pci1713", 0x1713, - IORANGE_171x, 1, TYPE_PCI1713, - 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000, - &range_pci1710_3, range_codes_pci1710_3, NULL, - 10000, 2048}, - {"pci1720", 0x1720, - IORANGE_1720, 0, TYPE_PCI1720, - 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff, - NULL, NULL, &range_pci1720, - 0, 0}, - {"pci1731", 0x1731, - IORANGE_171x, 1, TYPE_PCI171X, - 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000, - &range_pci17x1, range_codes_pci17x1, NULL, - 10000, 512}, - /* dummy entry corresponding to driver name */ - {.name = DRV_NAME}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) - -static struct comedi_driver driver_pci1710 = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = pci1710_attach, - .detach = pci1710_detach, - .num_names = n_boardtypes, - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), + [BOARD_PCI1710] = { + .name = "pci1710", + .have_irq = 1, + .cardtype = TYPE_PCI171X, + .n_aichan = 16, + .n_aichand = 8, + .n_aochan = 2, + .n_dichan = 16, + .n_dochan = 16, + .n_counter = 1, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci1710_3, + .rangecode_ai = range_codes_pci1710_3, + .rangelist_ao = &range_pci171x_da, + .ai_ns_min = 10000, + .fifo_half_size = 2048, + }, + [BOARD_PCI1710HG] = { + .name = "pci1710hg", + .have_irq = 1, + .cardtype = TYPE_PCI171X, + .n_aichan = 16, + .n_aichand = 8, + .n_aochan = 2, + .n_dichan = 16, + .n_dochan = 16, + .n_counter = 1, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci1710hg, + .rangecode_ai = range_codes_pci1710hg, + .rangelist_ao = &range_pci171x_da, + .ai_ns_min = 10000, + .fifo_half_size = 2048, + }, + [BOARD_PCI1711] = { + .name = "pci1711", + .have_irq = 1, + .cardtype = TYPE_PCI171X, + .n_aichan = 16, + .n_aochan = 2, + .n_dichan = 16, + .n_dochan = 16, + .n_counter = 1, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci17x1, + .rangecode_ai = range_codes_pci17x1, + .rangelist_ao = &range_pci171x_da, + .ai_ns_min = 10000, + .fifo_half_size = 512, + }, + [BOARD_PCI1713] = { + .name = "pci1713", + .have_irq = 1, + .cardtype = TYPE_PCI1713, + .n_aichan = 32, + .n_aichand = 16, + .ai_maxdata = 0x0fff, + .rangelist_ai = &range_pci1710_3, + .rangecode_ai = range_codes_pci1710_3, + .ai_ns_min = 10000, + .fifo_half_size = 2048, + }, + [BOARD_PCI1720] = { + .name = "pci1720", + .cardtype = TYPE_PCI1720, + .n_aochan = 4, + .ao_maxdata = 0x0fff, + .rangelist_ao = &range_pci1720, + }, + [BOARD_PCI1731] = { + .name = "pci1731", + .have_irq = 1, + .cardtype = TYPE_PCI171X, + .n_aichan = 16, + .n_dichan = 16, + .n_dochan = 16, + .ai_maxdata = 0x0fff, + .rangelist_ai = &range_pci17x1, + .rangecode_ai = range_codes_pci17x1, + .ai_ns_min = 10000, + .fifo_half_size = 512, + }, }; struct pci1710_private { - struct pci_dev *pcidev; /* ptr to PCI device */ - char valid; /* card is usable */ - char neverending_ai; /* we do unlimited AI */ unsigned int CntrlReg; /* Control register */ - unsigned int i8254_osc_base; /* frequence of onboard oscilator */ - unsigned int ai_do; /* what do AI? 0=nothing, 1 to 4 mode */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_act_chan; /* actual position in actual scan */ - unsigned int ai_buf_ptr; /* data buffer ptr in samples */ - unsigned char ai_eos; /* 1=EOS wake up */ unsigned char ai_et; unsigned int ai_et_CntrlReg; unsigned int ai_et_MuxVal; - unsigned int ai_et_div1, ai_et_div2; - unsigned int act_chanlist[32]; /* list of scaned channel */ - unsigned char act_chanlist_len; /* len of scanlist */ - unsigned char act_chanlist_pos; /* actual position in MUX list */ + unsigned int next_divisor1; + unsigned int next_divisor2; + unsigned int divisor1; + unsigned int divisor2; + unsigned int act_chanlist[32]; /* list of scanned channel */ + unsigned char saved_seglen; /* len of the non-repeating chanlist */ unsigned char da_ranges; /* copy of D/A outpit range register */ - unsigned int ai_scans; /* len of scanlist */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int ai_flags; /* flaglist */ - unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; - short ao_data[4]; /* data output buffer */ + unsigned short ao_data[4]; /* data output buffer */ unsigned int cnt0_write_wait; /* after a write, wait for update of the * internal state */ }; -#define devpriv ((struct pci1710_private *)dev->private) -#define this_board ((const struct boardtype *)dev->board_ptr) - -/* -============================================================================== -*/ - -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static int pci1710_reset(struct comedi_device *dev); -static int pci171x_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - /* used for gain list programming */ static const unsigned int muxonechan[] = { 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, @@ -336,19 +322,144 @@ static const unsigned int muxonechan[] = { 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f }; -/* -============================================================================== -*/ +static int pci171x_ai_dropout(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, + unsigned int val) +{ + const struct boardtype *board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + + if (board->cardtype != TYPE_PCI1713) { + if ((val & 0xf000) != devpriv->act_chanlist[chan]) { + dev_err(dev->class_dev, + "A/D data droput: received from channel %d, expected %d\n", + (val >> 12) & 0xf, + (devpriv->act_chanlist[chan] >> 12) & 0xf); + return -ENODATA; + } + } + return 0; +} + +static int pci171x_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + struct pci1710_private *devpriv = dev->private; + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int last_aref = CR_AREF(cmd->chanlist[0]); + unsigned int next_chan = (chan0 + 1) % s->n_chan; + unsigned int chansegment[32]; + unsigned int seglen; + int i; + + if (cmd->chanlist_len == 1) { + devpriv->saved_seglen = cmd->chanlist_len; + return 0; + } + + /* first channel is always ok */ + chansegment[0] = cmd->chanlist[0]; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (cmd->chanlist[0] == cmd->chanlist[i]) + break; /* we detected a loop, stop */ + + if (aref == AREF_DIFF && (chan & 1)) { + dev_err(dev->class_dev, + "Odd channel cannot be differential input!\n"); + return -EINVAL; + } + + if (last_aref == AREF_DIFF) + next_chan = (next_chan + 1) % s->n_chan; + if (chan != next_chan) { + dev_err(dev->class_dev, + "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", + i, chan, next_chan, chan0); + return -EINVAL; + } + + /* next correct channel in list */ + chansegment[i] = cmd->chanlist[i]; + last_aref = aref; + } + seglen = i; + + for (i = 0; i < cmd->chanlist_len; i++) { + if (cmd->chanlist[i] != chansegment[i % seglen]) { + dev_err(dev->class_dev, + "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", + i, CR_CHAN(chansegment[i]), + CR_RANGE(chansegment[i]), + CR_AREF(chansegment[i]), + CR_CHAN(cmd->chanlist[i % seglen]), + CR_RANGE(cmd->chanlist[i % seglen]), + CR_AREF(chansegment[i % seglen])); + return -EINVAL; + } + } + devpriv->saved_seglen = seglen; + + return 0; +} + +static void setup_channel_list(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chanlist, unsigned int n_chan, + unsigned int seglen) +{ + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + unsigned int i, range, chanprog; + + for (i = 0; i < seglen; i++) { /* store range list to card */ + chanprog = muxonechan[CR_CHAN(chanlist[i])]; + outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ + range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; + if (CR_AREF(chanlist[i]) == AREF_DIFF) + range |= 0x0020; + outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ + devpriv->act_chanlist[i] = + (CR_CHAN(chanlist[i]) << 12) & 0xf000; + } + for ( ; i < n_chan; i++) { /* store remainder of channel list */ + devpriv->act_chanlist[i] = + (CR_CHAN(chanlist[i]) << 12) & 0xf000; + } + + devpriv->ai_et_MuxVal = + CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); + /* select channel interval to scan */ + outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); +} + +static int pci171x_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI171x_STATUS); + if ((status & Status_FE) == 0) + return 0; + return -EBUSY; +} + static int pci171x_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, timeout; -#ifdef PCI171x_PARANOIDCHECK - unsigned int idata; -#endif + struct pci1710_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int ret = 0; + int i; - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n"); devpriv->CntrlReg &= Control_CNT0; devpriv->CntrlReg |= Control_SW; /* set software trigger */ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); @@ -357,54 +468,27 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, setup_channel_list(dev, s, &insn->chanspec, 1, 1); - DPRINTK("adv_pci1710 A ST=%4x IO=%x\n", - inw(dev->iobase + PCI171x_STATUS), - dev->iobase + PCI171x_STATUS); - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { + unsigned int val; + outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ - DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n, - inw(dev->iobase + PCI171x_STATUS)); - /* udelay(1); */ - DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n, - inw(dev->iobase + PCI171x_STATUS)); - timeout = 100; - while (timeout--) { - if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE)) - goto conv_finish; - if (!(timeout % 10)) - DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n, - timeout, - inw(dev->iobase + PCI171x_STATUS)); - } - comedi_error(dev, "A/D insn timeout"); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - data[n] = 0; - DPRINTK - ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", - n); - return -ETIME; - -conv_finish: -#ifdef PCI171x_PARANOIDCHECK - idata = inw(dev->iobase + PCI171x_AD_DATA); - if (this_board->cardtype != TYPE_PCI1713) - if ((idata & 0xf000) != devpriv->act_chanlist[0]) { - comedi_error(dev, "A/D insn data droput!"); - return -ETIME; - } - data[n] = idata & 0x0fff; -#else - data[n] = inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff; -#endif + ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0); + if (ret) + break; + + val = inw(dev->iobase + PCI171x_AD_DATA); + ret = pci171x_ai_dropout(dev, s, chan, val); + if (ret) + break; + + data[i] = val & s->maxdata; } outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n); - return n; + return ret ? ret : insn->n; } /* @@ -414,6 +498,8 @@ static int pci171x_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, chan, range, ofs; chan = CR_CHAN(insn->chanspec); @@ -429,11 +515,14 @@ static int pci171x_insn_write_ao(struct comedi_device *dev, outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); ofs = PCI171x_DA1; } + val = devpriv->ao_data[chan]; - for (n = 0; n < insn->n; n++) - outw(data[n], dev->iobase + ofs); + for (n = 0; n < insn->n; n++) { + val = data[n]; + outw(val, dev->iobase + ofs); + } - devpriv->ao_data[chan] = data[n]; + devpriv->ao_data[chan] = val; return n; @@ -446,6 +535,7 @@ static int pci171x_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; int n, chan; chan = CR_CHAN(insn->chanspec); @@ -464,24 +554,35 @@ static int pci171x_insn_bits_di(struct comedi_device *dev, { data[1] = inw(dev->iobase + PCI171x_DI); - return 2; + return insn->n; } -/* -============================================================================== -*/ static int pci171x_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI171x_DO); - } + data[1] = s->state; - return 2; + return insn->n; +} + +static void pci171x_start_pacer(struct comedi_device *dev, + bool load_counters) +{ + struct pci1710_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE; + + i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY); + + if (load_counters) { + i8254_write(timer_base, 1, 2, devpriv->divisor2); + i8254_write(timer_base, 1, 1, devpriv->divisor1); + } } /* @@ -516,6 +617,7 @@ static int pci171x_insn_counter_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; uint msb, lsb, ccntrl, status; lsb = data[0] & 0x00FF; @@ -547,6 +649,7 @@ static int pci171x_insn_counter_config(struct comedi_device *dev, { #ifdef unused /* This doesn't work like a normal Comedi counter config */ + struct pci1710_private *devpriv = dev->private; uint ccntrl = 0; devpriv->cnt0_write_wait = data[0] & 0x20; @@ -582,6 +685,8 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; + unsigned int val; int n, rangereg, chan; chan = CR_CHAN(insn->chanspec); @@ -591,13 +696,15 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, outb(rangereg, dev->iobase + PCI1720_RANGE); devpriv->da_ranges = rangereg; } + val = devpriv->ao_data[chan]; for (n = 0; n < insn->n; n++) { - outw(data[n], dev->iobase + PCI1720_DA0 + (chan << 1)); + val = data[n]; + outw(val, dev->iobase + PCI1720_DA0 + (chan << 1)); outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */ } - devpriv->ao_data[chan] = data[n]; + devpriv->ao_data[chan] = val; return n; } @@ -605,90 +712,85 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, /* ============================================================================== */ -static void interrupt_pci1710_every_sample(void *d) +static int pci171x_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - int m; -#ifdef PCI171x_PARANOIDCHECK - short sampl; -#endif + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; - DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n"); - m = inw(dev->iobase + PCI171x_STATUS); - if (m & Status_FE) { - printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m); - pci171x_ai_cancel(dev, s); + switch (this_board->cardtype) { + default: + devpriv->CntrlReg &= Control_CNT0; + devpriv->CntrlReg |= Control_SW; + + outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ + pci171x_start_pacer(dev, false); + outb(0, dev->iobase + PCI171x_CLRFIFO); + outb(0, dev->iobase + PCI171x_CLRINT); + break; + } + + devpriv->ai_act_scan = 0; + s->async->cur_chan = 0; + + return 0; +} + +static void pci1710_handle_every_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci1710_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int status; + unsigned int val; + int ret; + + status = inw(dev->iobase + PCI171x_STATUS); + if (status & Status_FE) { + dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } - if (m & Status_FF) { - printk - ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n", - dev->minor, m); - pci171x_ai_cancel(dev, s); + if (status & Status_FF) { + dev_dbg(dev->class_dev, + "A/D FIFO Full status (Fatal Error!) (%4x)\n", status); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - DPRINTK("FOR "); for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { -#ifdef PCI171x_PARANOIDCHECK - sampl = inw(dev->iobase + PCI171x_AD_DATA); - DPRINTK("%04x:", sampl); - if (this_board->cardtype != TYPE_PCI1713) - if ((sampl & 0xf000) != - devpriv->act_chanlist[s->async->cur_chan]) { - printk - ("comedi: A/D data dropout: received data from channel %d, expected %d!\n", - (sampl & 0xf000) >> 12, - (devpriv-> - act_chanlist[s-> - async->cur_chan] & 0xf000) >> - 12); - pci171x_ai_cancel(dev, s); - s->async->events |= - COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return; - } - DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr, - s->async->cur_chan, s->async->buf_int_count); - comedi_buf_put(s->async, sampl & 0x0fff); -#else - comedi_buf_put(s->async, - inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff); -#endif - ++s->async->cur_chan; + val = inw(dev->iobase + PCI171x_AD_DATA); + ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); + if (ret) { + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + break; + } + + comedi_buf_put(s, val & s->maxdata); - if (s->async->cur_chan >= devpriv->ai_n_chan) + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) s->async->cur_chan = 0; if (s->async->cur_chan == 0) { /* one scan done */ devpriv->ai_act_scan++; - DPRINTK - ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n", - s->async->buf_int_count, s->async->buf_int_ptr, - s->async->buf_user_count, s->async->buf_user_ptr); - DPRINTK("adv_pci1710 EDBG: EOS2\n"); - if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */ - pci171x_ai_cancel(dev, s); + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; + break; } } } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n"); - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -697,78 +799,58 @@ static void interrupt_pci1710_every_sample(void *d) static int move_block_from_fifo(struct comedi_device *dev, struct comedi_subdevice *s, int n, int turn) { - int i, j; -#ifdef PCI171x_PARANOIDCHECK - int sampl; -#endif - DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n, - turn); - j = s->async->cur_chan; + struct pci1710_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int val; + int ret; + int i; + for (i = 0; i < n; i++) { -#ifdef PCI171x_PARANOIDCHECK - sampl = inw(dev->iobase + PCI171x_AD_DATA); - if (this_board->cardtype != TYPE_PCI1713) - if ((sampl & 0xf000) != devpriv->act_chanlist[j]) { - printk - ("comedi%d: A/D FIFO data dropout: received data from channel %d, expected %d! (%d/%d/%d/%d/%d/%4x)\n", - dev->minor, (sampl & 0xf000) >> 12, - (devpriv->act_chanlist[j] & 0xf000) >> 12, - i, j, devpriv->ai_act_scan, n, turn, - sampl); - pci171x_ai_cancel(dev, s); - s->async->events |= - COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return 1; - } - comedi_buf_put(s->async, sampl & 0x0fff); -#else - comedi_buf_put(s->async, - inw(dev->iobase + PCI171x_AD_DATA) & 0x0fff); -#endif - j++; - if (j >= devpriv->ai_n_chan) { - j = 0; + val = inw(dev->iobase + PCI171x_AD_DATA); + + ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val); + if (ret) { + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return ret; + } + + comedi_buf_put(s, val & s->maxdata); + + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; devpriv->ai_act_scan++; } } - s->async->cur_chan = j; - DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n"); return 0; } -/* -============================================================================== -*/ -static void interrupt_pci1710_half_fifo(void *d) +static void pci1710_handle_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int m, samplesinbuf; - DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n"); m = inw(dev->iobase + PCI171x_STATUS); if (!(m & Status_FH)) { - printk("comedi%d: A/D FIFO not half full! (%4x)\n", - dev->minor, m); - pci171x_ai_cancel(dev, s); + dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } if (m & Status_FF) { - printk - ("comedi%d: A/D FIFO Full status (Fatal Error!) (%4x)\n", - dev->minor, m); - pci171x_ai_cancel(dev, s); + dev_dbg(dev->class_dev, + "A/D FIFO Full status (Fatal Error!) (%4x)\n", m); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } samplesinbuf = this_board->fifo_half_size; - if (samplesinbuf * sizeof(short) >= devpriv->ai_data_len) { - m = devpriv->ai_data_len / sizeof(short); + if (samplesinbuf * sizeof(short) >= s->async->prealloc_bufsz) { + m = s->async->prealloc_bufsz / sizeof(short); if (move_block_from_fifo(dev, s, m, 0)) return; samplesinbuf -= m; @@ -779,18 +861,16 @@ static void interrupt_pci1710_half_fifo(void *d) return; } - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan >= devpriv->ai_scans) { /* all data - sampled */ - pci171x_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return; - } + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + cfc_handle_events(dev, s); + return; + } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n"); - comedi_event(dev, s); + cfc_handle_events(dev, s); } /* @@ -799,143 +879,88 @@ static void interrupt_pci1710_half_fifo(void *d) static irqreturn_t interrupt_service_pci1710(int irq, void *d) { struct comedi_device *dev = d; + struct pci1710_private *devpriv = dev->private; + struct comedi_subdevice *s; + struct comedi_cmd *cmd; - DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n", - irq); if (!dev->attached) /* is device attached? */ return IRQ_NONE; /* no, exit */ - if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) /* is this interrupt from our board? */ - return IRQ_NONE; /* no, exit */ + s = dev->read_subdev; + cmd = &s->async->cmd; - DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n", - inw(dev->iobase + PCI171x_STATUS)); + /* is this interrupt from our board? */ + if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) + return IRQ_NONE; /* no, exit */ if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ devpriv->ai_et = 0; devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; /* set software trigger */ + devpriv->CntrlReg |= Control_SW; /* set software trigger */ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); devpriv->CntrlReg = devpriv->ai_et_CntrlReg; outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - /* start pacer */ - start_pacer(dev, 1, devpriv->ai_et_div1, devpriv->ai_et_div2); + pci171x_start_pacer(dev, true); return IRQ_HANDLED; } - if (devpriv->ai_eos) { /* We use FIFO half full INT or not? */ - interrupt_pci1710_every_sample(d); - } else { - interrupt_pci1710_half_fifo(d); - } - DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n"); + + if (cmd->flags & TRIG_WAKE_EOS) + pci1710_handle_every_sample(dev, s); + else + pci1710_handle_fifo(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ -static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) +static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned int divisor1 = 0, divisor2 = 0; - unsigned int seglen; + struct pci1710_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n", - mode); - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pci171x_start_pacer(dev, false); - seglen = check_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan); - if (seglen < 1) - return -EINVAL; - setup_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan, seglen); + setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len, + devpriv->saved_seglen); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - devpriv->ai_do = mode; - devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; - devpriv->neverending_ai = 0; devpriv->CntrlReg &= Control_CNT0; - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { /* don't we want wake up every scan? devpriv->ai_eos=1; */ - devpriv->ai_eos = 1; - } else { + if ((cmd->flags & TRIG_WAKE_EOS) == 0) devpriv->CntrlReg |= Control_ONEFH; - devpriv->ai_eos = 0; - } - if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; - /* well, user want neverending */ - else - devpriv->neverending_ai = 0; + devpriv->divisor1 = devpriv->next_divisor1; + devpriv->divisor2 = devpriv->next_divisor2; - switch (mode) { - case 1: - case 2: - if (devpriv->ai_timer1 < this_board->ai_ns_min) - devpriv->ai_timer1 = this_board->ai_ns_min; + if (cmd->convert_src == TRIG_TIMER) { devpriv->CntrlReg |= Control_PACER | Control_IRQEN; - if (mode == 2) { + if (cmd->start_src == TRIG_EXT) { devpriv->ai_et_CntrlReg = devpriv->CntrlReg; devpriv->CntrlReg &= ~(Control_PACER | Control_ONEFH | Control_GATE); devpriv->CntrlReg |= Control_EXT; devpriv->ai_et = 1; - } else { + } else { /* TRIG_NOW */ devpriv->ai_et = 0; } - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &devpriv->ai_timer1, - devpriv->ai_flags & TRIG_ROUND_MASK); - DPRINTK - ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n", - devpriv->i8254_osc_base, divisor1, divisor2, - devpriv->ai_timer1); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - if (mode != 2) { - /* start pacer */ - start_pacer(dev, mode, divisor1, divisor2); - } else { - devpriv->ai_et_div1 = divisor1; - devpriv->ai_et_div2 = divisor2; - } - break; - case 3: + + if (cmd->start_src == TRIG_NOW) + pci171x_start_pacer(dev, true); + } else { /* TRIG_EXT */ devpriv->CntrlReg |= Control_EXT | Control_IRQEN; outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); - break; } - DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n"); return 0; } -#ifdef PCI171X_EXTDEBUG -/* -============================================================================== -*/ -static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd) -{ - printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, - cmd->start_src, cmd->scan_begin_src, cmd->convert_src); - printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e, - cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); - printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, - cmd->scan_end_src); - printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", - e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); -} -#endif - /* ============================================================================== */ @@ -943,358 +968,75 @@ 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); + struct pci1710_private *devpriv = dev->private; int err = 0; - int tmp; - unsigned int divisor1 = 0, divisor2 = 0; - - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n"); -#ifdef PCI171X_EXTDEBUG - pci171x_cmdtest_out(-1, cmd); -#endif - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) { -#ifdef PCI171X_EXTDEBUG - pci171x_cmdtest_out(1, cmd); -#endif - DPRINTK - ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n", - err); - return 1; - } + unsigned int arg; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 1 : check if triggers are trivially valid */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) { - cmd->start_src = TRIG_NOW; - err++; - } + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + 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 (cmd->scan_begin_src != TRIG_FOLLOW) { - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } + if (err) + return 1; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; + /* step 2a: make sure trigger sources are unique */ - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* step 2b: and mutually compatible */ - if (err) { -#ifdef PCI171X_EXTDEBUG - pci171x_cmdtest_out(2, cmd); -#endif - DPRINTK - ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n", - err); + if (err) return 2; - } - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + this_board->ai_ns_min); + else /* TRIG_FOLLOW */ + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < this_board->ai_ns_min) { - cmd->convert_arg = this_board->ai_ns_min; - err++; - } - } else { /* TRIG_FOLLOW */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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) { -#ifdef PCI171X_EXTDEBUG - pci171x_cmdtest_out(3, cmd); -#endif - DPRINTK - ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n", - err); + if (err) return 3; - } /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->next_divisor1, + &devpriv->next_divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } - if (err) { - DPRINTK - ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n", - err); + if (err) return 4; - } - - /* step 5: complain about special chanlist considerations */ - - if (cmd->chanlist) { - if (!check_channel_list(dev, s, cmd->chanlist, - cmd->chanlist_len)) - return 5; /* incorrect channels list */ - } - - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n"); - return 0; -} - -/* -============================================================================== -*/ -static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - struct comedi_cmd *cmd = &s->async->cmd; - - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n"); - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; - devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; - - if (cmd->stop_src == TRIG_COUNT) - devpriv->ai_scans = cmd->stop_arg; - else - devpriv->ai_scans = 0; - - - if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 2, 3 */ - if (cmd->convert_src == TRIG_TIMER) { /* mode 1 and 2 */ - devpriv->ai_timer1 = cmd->convert_arg; - return pci171x_ai_docmd_and_mode(cmd->start_src == - TRIG_EXT ? 2 : 1, dev, - s); - } - if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ - return pci171x_ai_docmd_and_mode(3, dev, s); - } - } - - return -1; -} - -/* -============================================================================== - Check if channel list from user is builded correctly - If it's ok, then program scan/gain logic. - This works for all cards. -*/ -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) -{ - unsigned int chansegment[32]; - unsigned int i, nowmustbechan, seglen, segpos; - - DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan); - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - comedi_error(dev, "range/channel list is empty!"); - return 0; - } - - if (n_chan > 1) { - chansegment[0] = chanlist[0]; /* first channel is every time ok */ - for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { /* build part of chanlist */ - /* printk("%d. %d %d\n",i,CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */ - if (chanlist[0] == chanlist[i]) - break; /* we detect loop, this must by finish */ - if (CR_CHAN(chanlist[i]) & 1) /* odd channel cann't by differencial */ - if (CR_AREF(chanlist[i]) == AREF_DIFF) { - comedi_error(dev, - "Odd channel can't be differential input!\n"); - return 0; - } - nowmustbechan = - (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; - if (CR_AREF(chansegment[i - 1]) == AREF_DIFF) - nowmustbechan = (nowmustbechan + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */ - printk - ("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", - i, CR_CHAN(chanlist[i]), nowmustbechan, - CR_CHAN(chanlist[0])); - return 0; - } - chansegment[i] = chanlist[i]; /* well, this is next correct channel in list */ - } - - for (i = 0, segpos = 0; i < n_chan; i++) { /* check whole chanlist */ - /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(chanlist[i]),CR_RANGE(chanlist[i])); */ - if (chanlist[i] != chansegment[i % seglen]) { - printk - ("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", - i, CR_CHAN(chansegment[i]), - CR_RANGE(chansegment[i]), - CR_AREF(chansegment[i]), - CR_CHAN(chanlist[i % seglen]), - CR_RANGE(chanlist[i % seglen]), - CR_AREF(chansegment[i % seglen])); - return 0; /* chan/gain list is strange */ - } - } - } else { - seglen = 1; - } - return seglen; -} - -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen) -{ - unsigned int i, range, chanprog; - - DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan, - seglen); - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - - DPRINTK("SegLen: %d\n", seglen); - for (i = 0; i < seglen; i++) { /* store range list to card */ - chanprog = muxonechan[CR_CHAN(chanlist[i])]; - outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ - range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; - if (CR_AREF(chanlist[i]) == AREF_DIFF) - range |= 0x0020; - outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ -#ifdef PCI171x_PARANOIDCHECK - devpriv->act_chanlist[i] = - (CR_CHAN(chanlist[i]) << 12) & 0xf000; -#endif - DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, - devpriv->act_chanlist[i]); - } -#ifdef PCI171x_PARANOIDCHECK - for ( ; i < n_chan; i++) { /* store remainder of channel list */ - devpriv->act_chanlist[i] = - (CR_CHAN(chanlist[i]) << 12) & 0xf000; - } -#endif - - devpriv->ai_et_MuxVal = - CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); - outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); /* select channel interval to scan */ - DPRINTK("MUX: %4x L%4x.H%4x\n", - CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8), - CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1])); -} - -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) -{ - DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, - divisor1, divisor2); - outw(0xb4, dev->iobase + PCI171x_CNTCTRL); - outw(0x74, dev->iobase + PCI171x_CNTCTRL); - - if (mode == 1) { - outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2); - outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2); - outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1); - outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1); - } - DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n"); -} - -/* -============================================================================== -*/ -static int pci171x_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n"); - switch (this_board->cardtype) { - default: - devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; + /* Step 5: check channel list */ - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ - start_pacer(dev, -1, 0, 0); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - break; - } + err |= pci171x_ai_check_chanlist(dev, s, cmd); - devpriv->ai_do = 0; - devpriv->ai_act_scan = 0; - s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; - devpriv->neverending_ai = 0; + if (err) + return 5; - DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n"); return 0; } @@ -1303,13 +1045,15 @@ static int pci171x_ai_cancel(struct comedi_device *dev, */ static int pci171x_reset(struct comedi_device *dev) { - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n"); + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + outw(0x30, dev->iobase + PCI171x_CNTCTRL); devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ - start_pacer(dev, -1, 0, 0); /* stop 8254 */ + pci171x_start_pacer(dev, false); devpriv->da_ranges = 0; if (this_board->n_aochan) { outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF); /* set DACs to 0..5V */ @@ -1324,7 +1068,6 @@ static int pci171x_reset(struct comedi_device *dev) outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ - DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n"); return 0; } @@ -1333,7 +1076,8 @@ static int pci171x_reset(struct comedi_device *dev) */ static int pci1720_reset(struct comedi_device *dev) { - DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n"); + struct pci1710_private *devpriv = dev->private; + outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */ devpriv->da_ranges = 0xAA; outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */ @@ -1346,7 +1090,6 @@ static int pci1720_reset(struct comedi_device *dev) devpriv->ao_data[1] = 0x0800; devpriv->ao_data[2] = 0x0800; devpriv->ao_data[3] = 0x0800; - DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n"); return 0; } @@ -1355,108 +1098,40 @@ static int pci1720_reset(struct comedi_device *dev) */ static int pci1710_reset(struct comedi_device *dev) { - DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n"); + const struct boardtype *this_board = comedi_board(dev); + switch (this_board->cardtype) { case TYPE_PCI1720: return pci1720_reset(dev); default: return pci171x_reset(dev); } - DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n"); } -/* -============================================================================== -*/ -static int pci1710_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci1710_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct boardtype *this_board = NULL; + struct pci1710_private *devpriv; struct comedi_subdevice *s; int ret, subdev, n_subdevices; - unsigned int irq; - unsigned long iobase; - struct pci_dev *pcidev; - int opt_bus, opt_slot; - const char *errstr; - unsigned char pci_bus, pci_slot, pci_func; - int i; - int board_index; - printk("comedi%d: adv_pci1710: ", dev->minor); - - opt_bus = it->options[0]; - opt_slot = it->options[1]; + if (context < ARRAY_SIZE(boardtypes)) + this_board = &boardtypes[context]; + if (!this_board) + return -ENODEV; + dev->board_ptr = this_board; + dev->board_name = this_board->name; - ret = alloc_private(dev, sizeof(struct pci1710_private)); - if (ret < 0) { - printk(" - Allocation failed!\n"); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - } - - /* Look for matching PCI device */ - errstr = "not found!"; - pcidev = NULL; - board_index = this_board - boardtypes; - while (NULL != (pcidev = pci_get_device(PCI_VENDOR_ID_ADVANTECH, - PCI_ANY_ID, pcidev))) { - if (strcmp(this_board->name, DRV_NAME) == 0) { - for (i = 0; i < n_boardtypes; ++i) { - if (pcidev->device == boardtypes[i].device_id) { - board_index = i; - break; - } - } - if (i == n_boardtypes) - continue; - } else { - if (pcidev->device != boardtypes[board_index].device_id) - continue; - } - /* Found matching vendor/device. */ - if (opt_bus || opt_slot) { - /* Check bus/slot. */ - if (opt_bus != pcidev->bus->number - || opt_slot != PCI_SLOT(pcidev->devfn)) - continue; /* no match */ - } - /* - * Look for device that isn't in use. - * Enable PCI device and request regions. - */ - if (comedi_pci_enable(pcidev, DRV_NAME)) { - errstr = - "failed to enable PCI device and request regions!"; - continue; - } - /* fixup board_ptr in case we were using the dummy entry with the driver name */ - dev->board_ptr = &boardtypes[board_index]; - break; - } - - if (!pcidev) { - if (opt_bus || opt_slot) { - printk(" - Card at b:s %d:%d %s\n", - opt_bus, opt_slot, errstr); - } else { - printk(" - Card %s\n", errstr); - } - return -EIO; - } - - pci_bus = pcidev->bus->number; - pci_slot = PCI_SLOT(pcidev->devfn); - pci_func = PCI_FUNC(pcidev->devfn); - irq = pcidev->irq; - iobase = pci_resource_start(pcidev, 2); - - printk(", b:s:f=%d:%d:%d, io=0x%4lx", pci_bus, pci_slot, pci_func, - iobase); - - dev->iobase = iobase; - - dev->board_name = this_board->name; - devpriv->pcidev = pcidev; + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 2); n_subdevices = 0; if (this_board->n_aichan) @@ -1470,63 +1145,44 @@ static int pci1710_attach(struct comedi_device *dev, if (this_board->n_counter) n_subdevices++; - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) { - printk(" - Allocation failed!\n"); + ret = comedi_alloc_subdevices(dev, n_subdevices); + if (ret) return ret; - } pci1710_reset(dev); - if (this_board->have_irq) { - if (irq) { - if (request_irq(irq, interrupt_service_pci1710, - IRQF_SHARED, "Advantech PCI-1710", - dev)) { - printk - (", unable to allocate IRQ %d, DISABLING IT", - irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(", irq=%u", irq); - } - } else { - printk(", IRQ disabled"); - } - } else { - irq = 0; + if (this_board->have_irq && pcidev->irq) { + ret = request_irq(pcidev->irq, interrupt_service_pci1710, + IRQF_SHARED, dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; } - dev->irq = irq; - - printk(".\n"); - subdev = 0; if (this_board->n_aichan) { - s = dev->subdevices + subdev; - dev->read_subdev = s; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; if (this_board->n_aichand) s->subdev_flags |= SDF_DIFF; s->n_chan = this_board->n_aichan; s->maxdata = this_board->ai_maxdata; - s->len_chanlist = this_board->n_aichan; s->range_table = this_board->rangelist_ai; - s->cancel = pci171x_ai_cancel; s->insn_read = pci171x_insn_read_ai; - if (irq) { + if (dev->irq) { + dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; s->do_cmdtest = pci171x_ai_cmdtest; s->do_cmd = pci171x_ai_cmd; + s->cancel = pci171x_ai_cancel; } - devpriv->i8254_osc_base = 100; /* 100ns=10MHz */ subdev++; } if (this_board->n_aochan) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->n_aochan; @@ -1546,35 +1202,31 @@ static int pci1710_attach(struct comedi_device *dev, } if (this_board->n_dichan) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->n_dichan; s->maxdata = 1; s->len_chanlist = this_board->n_dichan; s->range_table = &range_digital; - s->io_bits = 0; /* all bits input */ s->insn_bits = pci171x_insn_bits_di; subdev++; } if (this_board->n_dochan) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->n_dochan; s->maxdata = 1; s->len_chanlist = this_board->n_dochan; s->range_table = &range_digital; - /* all bits output */ - s->io_bits = (1 << this_board->n_dochan) - 1; - s->state = 0; s->insn_bits = pci171x_insn_bits_do; subdev++; } if (this_board->n_counter) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = this_board->n_counter; @@ -1587,76 +1239,99 @@ static int pci1710_attach(struct comedi_device *dev, subdev++; } - devpriv->valid = 1; - - return 0; -} - -/* -============================================================================== -*/ -static int pci1710_detach(struct comedi_device *dev) -{ - - if (dev->private) { - if (devpriv->valid) - pci1710_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv->pcidev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pcidev); - - pci_dev_put(devpriv->pcidev); - } - } - return 0; } -/* -============================================================================== -*/ -static int __devinit driver_pci1710_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_pci1710.driver_name); -} - -static void __devexit driver_pci1710_pci_remove(struct pci_dev *dev) +static void pci1710_detach(struct comedi_device *dev) { - comedi_pci_auto_unconfig(dev); + if (dev->iobase) + pci1710_reset(dev); + if (dev->irq) + free_irq(dev->irq, dev); + comedi_pci_disable(dev); } -static struct pci_driver driver_pci1710_pci_driver = { - .id_table = pci1710_pci_table, - .probe = &driver_pci1710_pci_probe, - .remove = __devexit_p(&driver_pci1710_pci_remove) +static struct comedi_driver adv_pci1710_driver = { + .driver_name = "adv_pci1710", + .module = THIS_MODULE, + .auto_attach = pci1710_auto_attach, + .detach = pci1710_detach, }; -static int __init driver_pci1710_init_module(void) +static int adv_pci1710_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_pci1710); - if (retval < 0) - return retval; - - driver_pci1710_pci_driver.name = (char *)driver_pci1710.driver_name; - return pci_register_driver(&driver_pci1710_pci_driver); + return comedi_pci_auto_config(dev, &adv_pci1710_driver, + id->driver_data); } -static void __exit driver_pci1710_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci1710_pci_driver); - comedi_driver_unregister(&driver_pci1710); -} +static const struct pci_device_id adv_pci1710_pci_table[] = { + { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050), + .driver_data = BOARD_PCI1710, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0x0000), + .driver_data = BOARD_PCI1710, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0xb100), + .driver_data = BOARD_PCI1710, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0xb200), + .driver_data = BOARD_PCI1710, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0xc100), + .driver_data = BOARD_PCI1710, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0xc200), + .driver_data = BOARD_PCI1710, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100), + .driver_data = BOARD_PCI1710, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0x0002), + .driver_data = BOARD_PCI1710HG, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0xb102), + .driver_data = BOARD_PCI1710HG, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0xb202), + .driver_data = BOARD_PCI1710HG, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0xc102), + .driver_data = BOARD_PCI1710HG, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, + PCI_VENDOR_ID_ADVANTECH, 0xc202), + .driver_data = BOARD_PCI1710HG, + }, { + PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102), + .driver_data = BOARD_PCI1710HG, + }, + { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 }, + { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 }, + { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 }, + { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table); -module_init(driver_pci1710_init_module); -module_exit(driver_pci1710_cleanup_module); -/* -============================================================================== -*/ +static struct pci_driver adv_pci1710_pci_driver = { + .name = "adv_pci1710", + .id_table = adv_pci1710_pci_table, + .probe = adv_pci1710_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index 1b5682104a0..07b107d1ab3 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -1,4 +1,4 @@ -/******************************************************************************* +/* comedi/drivers/pci1723.c COMEDI - Linux Control and Measurement Device Interface @@ -13,12 +13,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*******************************************************************************/ +*/ /* Driver: adv_pci1723 Description: Advantech PCI-1723 @@ -48,16 +43,10 @@ TODO: 3. Implement calibration. */ -#include "../comedidev.h" - -#include "comedi_pci.h" +#include <linux/module.h> +#include <linux/pci.h> -#define PCI_VENDOR_ID_ADVANTECH 0x13fe /* Advantech PCI vendor ID */ - -/* hardware types of the cards */ -#define TYPE_PCI1723 0 - -#define IORANGE_1723 0x2A +#include "../comedidev.h" /* all the registers for the pci1723 board */ #define PCI1723_DA(N) ((N)<<1) /* W: D/A register N (0 to 7) */ @@ -114,94 +103,18 @@ TODO: #define PCI1723_SELECT_CALIBRATION 0x28 /* Select the calibration Ref_V */ -/* static unsigned short pci_list_builded=0; =1 list of card is know */ - -static const struct comedi_lrange range_pci1723 = { 1, { - BIP_RANGE(10) - } -}; - -/* - * Board descriptions for pci1723 boards. - */ -struct pci1723_board { - const char *name; - int vendor_id; /* PCI vendor a device ID of card */ - int device_id; - int iorange; - char cardtype; - int n_aochan; /* num of D/A chans */ - int n_diochan; /* num of DIO chans */ - int ao_maxdata; /* resolution of D/A */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ -}; - -static const struct pci1723_board boardtypes[] = { - { - .name = "pci1723", - .vendor_id = PCI_VENDOR_ID_ADVANTECH, - .device_id = 0x1723, - .iorange = IORANGE_1723, - .cardtype = TYPE_PCI1723, - .n_aochan = 8, - .n_diochan = 16, - .ao_maxdata = 0xffff, - .rangelist_ao = &range_pci1723, - }, -}; - -/* - * This is used by modprobe to translate PCI IDs to drivers. - * Should only be used for PCI and ISA-PnP devices - */ -static DEFINE_PCI_DEVICE_TABLE(pci1723_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci1723_pci_table); - -/* - * 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 int pci1723_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci1723_detach(struct comedi_device *dev); - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pci1723_board)) - -static struct comedi_driver driver_pci1723 = { - .driver_name = "adv_pci1723", - .module = THIS_MODULE, - .attach = pci1723_attach, - .detach = pci1723_detach, -}; - -/* This structure is for data unique to this hardware driver. */ struct pci1723_private { - int valid; /* card is usable; */ - - struct pci_dev *pcidev; unsigned char da_range[8]; /* D/A output range for each channel */ - - short ao_data[8]; /* data output buffer */ + unsigned short ao_data[8]; /* data output buffer */ }; -/* The following macro to make it easy to access the private structure. */ -#define devpriv ((struct pci1723_private *)dev->private) - -#define this_board boardtypes - /* * The pci1723 card reset; */ static int pci1723_reset(struct comedi_device *dev) { + struct pci1723_private *devpriv = dev->private; int i; - DPRINTK("adv_pci1723 EDBG: BGN: pci1723_reset(...)\n"); outw(0x01, dev->iobase + PCI1723_SYN_SET); /* set synchronous output mode */ @@ -223,7 +136,6 @@ static int pci1723_reset(struct comedi_device *dev) /* set asynchronous output mode */ outw(0, dev->iobase + PCI1723_SYN_SET); - DPRINTK("adv_pci1723 EDBG: END: pci1723_reset(...)\n"); return 0; } @@ -231,10 +143,10 @@ static int pci1723_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1723_private *devpriv = dev->private; int n, chan; chan = CR_CHAN(insn->chanspec); - DPRINTK(" adv_PCI1723 DEBUG: pci1723_insn_read_ao() ----- \n"); for (n = 0; n < insn->n; n++) data[n] = devpriv->ao_data[chan]; @@ -248,11 +160,10 @@ static int pci1723_ao_write_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1723_private *devpriv = dev->private; int n, chan; chan = CR_CHAN(insn->chanspec); - DPRINTK("PCI1723: the pci1723_ao_write_winsn() ------\n"); - for (n = 0; n < insn->n; n++) { devpriv->ao_data[chan] = data[n]; @@ -269,269 +180,143 @@ static int pci1723_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int mask; - unsigned int bits; - unsigned short dio_mode; + unsigned short mode; + int ret; - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x00FF) - bits = 0x00FF; + if (chan < 8) + mask = 0x00ff; else - bits = 0xFF00; + mask = 0xff00; - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; /* update hardware DIO mode */ - dio_mode = 0x0000; /* low byte output, high byte output */ - if ((s->io_bits & 0x00FF) == 0) - dio_mode |= 0x0001; /* low byte input */ - if ((s->io_bits & 0xFF00) == 0) - dio_mode |= 0x0002; /* high byte input */ - outw(dio_mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET); - return 1; + mode = 0x0000; /* assume output */ + if (!(s->io_bits & 0x00ff)) + mode |= 0x0001; /* low byte input */ + if (!(s->io_bits & 0xff00)) + mode |= 0x0002; /* high byte input */ + outw(mode, dev->iobase + PCI1723_DIGITAL_IO_PORT_SET); + + return insn->n; } -/* - digital i/o bits read/write -*/ static int pci1723_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + PCI1723_WRITE_DIGITAL_OUTPUT_CMD); - } + data[1] = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); - return 2; + + return insn->n; } -/* - * Attach is called by the Comedi core to configure the driver - * for a pci1723 board. - */ -static int pci1723_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci1723_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct pci1723_private *devpriv; struct comedi_subdevice *s; - int ret, subdev, n_subdevices; - struct pci_dev *pcidev; - unsigned int iobase; - unsigned char pci_bus, pci_slot, pci_func; - int opt_bus, opt_slot; - const char *errstr; - - printk(KERN_ERR "comedi%d: adv_pci1723: board=%s", - dev->minor, this_board->name); - - opt_bus = it->options[0]; - opt_slot = it->options[1]; - - ret = alloc_private(dev, sizeof(struct pci1723_private)); - if (ret < 0) { - printk(" - Allocation failed!\n"); - return -ENOMEM; - } - - /* Look for matching PCI device */ - errstr = "not found!"; - pcidev = NULL; - while (NULL != (pcidev = - pci_get_device(PCI_VENDOR_ID_ADVANTECH, - this_board->device_id, pcidev))) { - /* Found matching vendor/device. */ - if (opt_bus || opt_slot) { - /* Check bus/slot. */ - if (opt_bus != pcidev->bus->number - || opt_slot != PCI_SLOT(pcidev->devfn)) - continue; /* no match */ - } - /* - * Look for device that isn't in use. - * Enable PCI device and request regions. - */ - if (comedi_pci_enable(pcidev, "adv_pci1723")) { - errstr = - "failed to enable PCI device and request regions!"; - continue; - } - break; - } - - if (!pcidev) { - if (opt_bus || opt_slot) { - printk(KERN_ERR " - Card at b:s %d:%d %s\n", - opt_bus, opt_slot, errstr); - } else { - printk(KERN_ERR " - Card %s\n", errstr); - } - return -EIO; - } - - pci_bus = pcidev->bus->number; - pci_slot = PCI_SLOT(pcidev->devfn); - pci_func = PCI_FUNC(pcidev->devfn); - iobase = pci_resource_start(pcidev, 2); - - printk(KERN_ERR ", b:s:f=%d:%d:%d, io=0x%4x", - pci_bus, pci_slot, pci_func, iobase); - - dev->iobase = iobase; - - dev->board_name = this_board->name; - devpriv->pcidev = pcidev; + int ret; - n_subdevices = 0; - - if (this_board->n_aochan) - n_subdevices++; - if (this_board->n_diochan) - n_subdevices++; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) { - printk(" - Allocation failed!\n"); + ret = comedi_pci_enable(dev); + if (ret) return ret; - } + dev->iobase = pci_resource_start(pcidev, 2); - pci1723_reset(dev); - subdev = 0; - if (this_board->n_aochan) { - s = dev->subdevices + subdev; - dev->write_subdev = s; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_aochan; - s->maxdata = this_board->ao_maxdata; - s->len_chanlist = this_board->n_aochan; - s->range_table = this_board->rangelist_ao; - - s->insn_write = pci1723_ao_write_winsn; - s->insn_read = pci1723_insn_read_ao; - - /* read DIO config */ - switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) - & 0x03) { - case 0x00: /* low byte output, high byte output */ - s->io_bits = 0xFFFF; - break; - case 0x01: /* low byte input, high byte output */ - s->io_bits = 0xFF00; - break; - case 0x02: /* low byte output, high byte input */ - s->io_bits = 0x00FF; - break; - case 0x03: /* low byte input, high byte input */ - s->io_bits = 0x0000; - break; - } - /* read DIO port state */ - s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); - - subdev++; - } + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; - if (this_board->n_diochan) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_diochan; - s->maxdata = 1; - s->len_chanlist = this_board->n_diochan; - s->range_table = &range_digital; - s->insn_config = pci1723_dio_insn_config; - s->insn_bits = pci1723_dio_insn_bits; - subdev++; + s = &dev->subdevices[0]; + dev->write_subdev = s; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 8; + s->maxdata = 0xffff; + s->len_chanlist = 8; + s->range_table = &range_bipolar10; + s->insn_write = pci1723_ao_write_winsn; + s->insn_read = pci1723_insn_read_ao; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->len_chanlist = 16; + s->range_table = &range_digital; + s->insn_config = pci1723_dio_insn_config; + s->insn_bits = pci1723_dio_insn_bits; + + /* read DIO config */ + switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) & 0x03) { + case 0x00: /* low byte output, high byte output */ + s->io_bits = 0xFFFF; + break; + case 0x01: /* low byte input, high byte output */ + s->io_bits = 0xFF00; + break; + case 0x02: /* low byte output, high byte input */ + s->io_bits = 0x00FF; + break; + case 0x03: /* low byte input, high byte input */ + s->io_bits = 0x0000; + break; } - - devpriv->valid = 1; + /* read DIO port state */ + s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); pci1723_reset(dev); return 0; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pci1723_detach(struct comedi_device *dev) -{ - printk(KERN_ERR "comedi%d: pci1723: remove\n", dev->minor); - - if (dev->private) { - if (devpriv->valid) - pci1723_reset(dev); - - if (devpriv->pcidev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pcidev); - pci_dev_put(devpriv->pcidev); - } - } - - return 0; -} - -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_pci1723_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static void pci1723_detach(struct comedi_device *dev) { - return comedi_pci_auto_config(dev, driver_pci1723.driver_name); + if (dev->iobase) + pci1723_reset(dev); + comedi_pci_disable(dev); } -static void __devexit driver_pci1723_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_pci1723_pci_driver = { - .id_table = pci1723_pci_table, - .probe = &driver_pci1723_pci_probe, - .remove = __devexit_p(&driver_pci1723_pci_remove) +static struct comedi_driver adv_pci1723_driver = { + .driver_name = "adv_pci1723", + .module = THIS_MODULE, + .auto_attach = pci1723_auto_attach, + .detach = pci1723_detach, }; -static int __init driver_pci1723_init_module(void) +static int adv_pci1723_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_pci1723); - if (retval < 0) - return retval; - - driver_pci1723_pci_driver.name = (char *)driver_pci1723.driver_name; - return pci_register_driver(&driver_pci1723_pci_driver); + return comedi_pci_auto_config(dev, &adv_pci1723_driver, + id->driver_data); } -static void __exit driver_pci1723_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci1723_pci_driver); - comedi_driver_unregister(&driver_pci1723); -} +static const struct pci_device_id adv_pci1723_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1723) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adv_pci1723_pci_table); -module_init(driver_pci1723_init_module); -module_exit(driver_pci1723_cleanup_module); +static struct pci_driver adv_pci1723_pci_driver = { + .name = "adv_pci1723", + .id_table = adv_pci1723_pci_table, + .probe = adv_pci1723_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adv_pci1723_driver, adv_pci1723_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c new file mode 100644 index 00000000000..af670acb03d --- /dev/null +++ b/drivers/staging/comedi/drivers/adv_pci1724.c @@ -0,0 +1,401 @@ +/* + comedi/drivers/adv_pci1724.c + This is a driver for the Advantech PCI-1724U card. + + Author: Frank Mori Hess <fmh6jj@gmail.com> + Copyright (C) 2013 GnuBIO Inc + + COMEDI - Linux Control and Measurement Device Interface + Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +/* + +Driver: adv_1724 +Description: Advantech PCI-1724U +Author: Frank Mori Hess <fmh6jj@gmail.com> +Status: works +Updated: 2013-02-09 +Devices: [Advantech] PCI-1724U (adv_pci1724) + +Subdevice 0 is the analog output. +Subdevice 1 is the offset calibration for the analog output. +Subdevice 2 is the gain calibration for the analog output. + +The calibration offset and gains have quite a large effect +on the analog output, so it is possible to adjust the analog output to +have an output range significantly different from the board's +nominal output ranges. For a calibrated +/- 10V range, the analog +output's offset will be set somewhere near mid-range (0x2000) and its +gain will be near maximum (0x3fff). + +There is really no difference between the board's documented 0-20mA +versus 4-20mA output ranges. To pick one or the other is simply a matter +of adjusting the offset and gain calibration until the board outputs in +the desired range. + +Configuration options: + None + +Manual configuration of comedi devices is not supported by this driver; +supported PCI devices are configured as comedi devices automatically. + +*/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/pci.h> + +#include "../comedidev.h" + +#define PCI_VENDOR_ID_ADVANTECH 0x13fe + +#define NUM_AO_CHANNELS 32 + +/* register offsets */ +enum board_registers { + DAC_CONTROL_REG = 0x0, + SYNC_OUTPUT_REG = 0x4, + EEPROM_CONTROL_REG = 0x8, + SYNC_OUTPUT_TRIGGER_REG = 0xc, + BOARD_ID_REG = 0x10 +}; + +/* bit definitions for registers */ +enum dac_control_contents { + DAC_DATA_MASK = 0x3fff, + DAC_DESTINATION_MASK = 0xc000, + DAC_NORMAL_MODE = 0xc000, + DAC_OFFSET_MODE = 0x8000, + DAC_GAIN_MODE = 0x4000, + DAC_CHANNEL_SELECT_MASK = 0xf0000, + DAC_GROUP_SELECT_MASK = 0xf00000 +}; + +static uint32_t dac_data_bits(uint16_t dac_data) +{ + return dac_data & DAC_DATA_MASK; +} + +static uint32_t dac_channel_select_bits(unsigned channel) +{ + return (channel << 16) & DAC_CHANNEL_SELECT_MASK; +} + +static uint32_t dac_group_select_bits(unsigned group) +{ + return (1 << (20 + group)) & DAC_GROUP_SELECT_MASK; +} + +static uint32_t dac_channel_and_group_select_bits(unsigned comedi_channel) +{ + return dac_channel_select_bits(comedi_channel % 8) | + dac_group_select_bits(comedi_channel / 8); +} + +enum sync_output_contents { + SYNC_MODE = 0x1, + DAC_BUSY = 0x2, /* dac state machine is not ready */ +}; + +enum sync_output_trigger_contents { + SYNC_TRIGGER_BITS = 0x0 /* any value works */ +}; + +enum board_id_contents { + BOARD_ID_MASK = 0xf +}; + +static const struct comedi_lrange ao_ranges_1724 = { + 4, { + BIP_RANGE(10), + RANGE_mA(0, 20), + RANGE_mA(4, 20), + RANGE_unitless(0, 1) + } +}; + +/* this structure is for data unique to this hardware driver. */ +struct adv_pci1724_private { + int ao_value[NUM_AO_CHANNELS]; + int offset_value[NUM_AO_CHANNELS]; + int gain_value[NUM_AO_CHANNELS]; +}; + +static int wait_for_dac_idle(struct comedi_device *dev) +{ + static const int timeout = 10000; + int i; + + for (i = 0; i < timeout; ++i) { + if ((inl(dev->iobase + SYNC_OUTPUT_REG) & DAC_BUSY) == 0) + break; + udelay(1); + } + if (i == timeout) { + comedi_error(dev, "Timed out waiting for dac to become idle."); + return -EIO; + } + return 0; +} + +static int set_dac(struct comedi_device *dev, unsigned mode, unsigned channel, + unsigned data) +{ + int retval; + unsigned control_bits; + + retval = wait_for_dac_idle(dev); + if (retval < 0) + return retval; + + control_bits = mode; + control_bits |= dac_channel_and_group_select_bits(channel); + control_bits |= dac_data_bits(data); + outl(control_bits, dev->iobase + DAC_CONTROL_REG); + return 0; +} + +static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct adv_pci1724_private *devpriv = dev->private; + int channel = CR_CHAN(insn->chanspec); + int retval; + int i; + + /* turn off synchronous mode */ + outl(0, dev->iobase + SYNC_OUTPUT_REG); + + for (i = 0; i < insn->n; ++i) { + retval = set_dac(dev, DAC_NORMAL_MODE, channel, data[i]); + if (retval < 0) + return retval; + devpriv->ao_value[channel] = data[i]; + } + return insn->n; +} + +static int ao_readback_insn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct adv_pci1724_private *devpriv = dev->private; + int channel = CR_CHAN(insn->chanspec); + int i; + + if (devpriv->ao_value[channel] < 0) { + comedi_error(dev, + "Cannot read back channels which have not yet been written to."); + return -EIO; + } + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_value[channel]; + + return insn->n; +} + +static int offset_write_insn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct adv_pci1724_private *devpriv = dev->private; + int channel = CR_CHAN(insn->chanspec); + int retval; + int i; + + /* turn off synchronous mode */ + outl(0, dev->iobase + SYNC_OUTPUT_REG); + + for (i = 0; i < insn->n; ++i) { + retval = set_dac(dev, DAC_OFFSET_MODE, channel, data[i]); + if (retval < 0) + return retval; + devpriv->offset_value[channel] = data[i]; + } + + return insn->n; +} + +static int offset_read_insn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct adv_pci1724_private *devpriv = dev->private; + unsigned int channel = CR_CHAN(insn->chanspec); + int i; + + if (devpriv->offset_value[channel] < 0) { + comedi_error(dev, + "Cannot read back channels which have not yet been written to."); + return -EIO; + } + for (i = 0; i < insn->n; i++) + data[i] = devpriv->offset_value[channel]; + + return insn->n; +} + +static int gain_write_insn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct adv_pci1724_private *devpriv = dev->private; + int channel = CR_CHAN(insn->chanspec); + int retval; + int i; + + /* turn off synchronous mode */ + outl(0, dev->iobase + SYNC_OUTPUT_REG); + + for (i = 0; i < insn->n; ++i) { + retval = set_dac(dev, DAC_GAIN_MODE, channel, data[i]); + if (retval < 0) + return retval; + devpriv->gain_value[channel] = data[i]; + } + + return insn->n; +} + +static int gain_read_insn(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_insn *insn, + unsigned int *data) +{ + struct adv_pci1724_private *devpriv = dev->private; + unsigned int channel = CR_CHAN(insn->chanspec); + int i; + + if (devpriv->gain_value[channel] < 0) { + comedi_error(dev, + "Cannot read back channels which have not yet been written to."); + return -EIO; + } + for (i = 0; i < insn->n; i++) + data[i] = devpriv->gain_value[channel]; + + return insn->n; +} + +/* Allocate and initialize the subdevice structures. + */ +static int setup_subdevices(struct comedi_device *dev) +{ + struct comedi_subdevice *s; + int ret; + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + /* analog output subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; + s->n_chan = NUM_AO_CHANNELS; + s->maxdata = 0x3fff; + s->range_table = &ao_ranges_1724; + s->insn_read = ao_readback_insn; + s->insn_write = ao_winsn; + + /* offset calibration */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = NUM_AO_CHANNELS; + s->insn_read = offset_read_insn; + s->insn_write = offset_write_insn; + s->maxdata = 0x3fff; + + /* gain calibration */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = NUM_AO_CHANNELS; + s->insn_read = gain_read_insn; + s->insn_write = gain_write_insn; + s->maxdata = 0x3fff; + + return 0; +} + +static int adv_pci1724_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct adv_pci1724_private *devpriv; + int i; + int retval; + unsigned int board_id; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + /* init software copies of output values to indicate we don't know + * what the output value is since it has never been written. */ + for (i = 0; i < NUM_AO_CHANNELS; ++i) { + devpriv->ao_value[i] = -1; + devpriv->offset_value[i] = -1; + devpriv->gain_value[i] = -1; + } + + retval = comedi_pci_enable(dev); + if (retval) + return retval; + + dev->iobase = pci_resource_start(pcidev, 2); + board_id = inl(dev->iobase + BOARD_ID_REG) & BOARD_ID_MASK; + dev_info(dev->class_dev, "board id: %d\n", board_id); + + retval = setup_subdevices(dev); + if (retval < 0) + return retval; + + dev_info(dev->class_dev, "%s (pci %s) attached, board id: %u\n", + dev->board_name, pci_name(pcidev), board_id); + return 0; +} + +static struct comedi_driver adv_pci1724_driver = { + .driver_name = "adv_pci1724", + .module = THIS_MODULE, + .auto_attach = adv_pci1724_auto_attach, + .detach = comedi_pci_disable, +}; + +static int adv_pci1724_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &adv_pci1724_driver, + id->driver_data); +} + +static const struct pci_device_id adv_pci1724_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1724) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adv_pci1724_pci_table); + +static struct pci_driver adv_pci1724_pci_driver = { + .name = "adv_pci1724", + .id_table = adv_pci1724_pci_table, + .probe = adv_pci1724_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; + +module_comedi_pci_driver(adv_pci1724_driver, adv_pci1724_pci_driver); + +MODULE_AUTHOR("Frank Mori Hess <fmh6jj@gmail.com>"); +MODULE_DESCRIPTION("Advantech PCI-1724U Comedi driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index d23799be7ce..2d966a87f2e 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -8,16 +8,16 @@ /* Driver: adv_pci_dio Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U, - PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, - PCI-1754, PCI-1756, PCI-1762 + PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752, + PCI-1753/E, PCI-1754, PCI-1756, PCI-1760, PCI-1762 Author: Michal Dobes <dobes@tesnet.cz> Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733, - PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750, + PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752, PCI-1753, PCI-1753+PCI-1753E, PCI-1754, PCI-1756, PCI-1760, PCI-1762 Status: untested -Updated: Tue, 04 May 2010 13:00:00 +0000 +Updated: Mon, 09 Jan 2012 12:40:46 +0000 This driver supports now only insn interface for DI/DO/DIO. @@ -29,28 +29,19 @@ Configuration options: */ -#include "../comedidev.h" - +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> -#include "comedi_pci.h" +#include "../comedidev.h" + #include "8255.h" #include "8253.h" -#undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */ - -#undef DPRINTK -#ifdef PCI_DIO_EXTDEBUG -#define DPRINTK(fmt, args...) printk(fmt, ## args) -#else -#define DPRINTK(fmt, args...) -#endif - -#define PCI_VENDOR_ID_ADVANTECH 0x13fe - /* hardware types of the cards */ enum hw_cards_id { TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736, + TYPE_PCI1739, TYPE_PCI1750, TYPE_PCI1751, TYPE_PCI1752, @@ -109,6 +100,12 @@ enum hw_io_access { #define PCI1736_BOARDID 4 /* R: Board I/D switch for 1736UP */ #define PCI1736_MAINREG 0 /* Normal register (2) doesn't work */ +/* Advantech PCI-1739U */ +#define PCI1739_DIO 0 /* R/W: begin of 8255 registers block */ +#define PCI1739_ICR 32 /* W: Interrupt control register */ +#define PCI1739_ISR 32 /* R: Interrupt status register */ +#define PCI1739_BOARDID 8 /* R: Board I/D switch for 1739U */ + /* Advantech PCI-1750 */ #define PCI1750_IDI 0 /* R: Isolated digital input 0-15 */ #define PCI1750_IDO 0 /* W: Isolated digital output 0-15 */ @@ -230,10 +227,6 @@ enum hw_io_access { #define OMBCMD_RETRY 0x03 /* 3 times try request before error */ -static int pci_dio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci_dio_detach(struct comedi_device *dev); - struct diosubd_data { int chans; /* num of chans */ int addr; /* PCI address ofset */ @@ -244,10 +237,9 @@ struct diosubd_data { struct dio_boardtype { const char *name; /* board name */ - int vendor_id; /* vendor/device PCI ID */ - int device_id; int main_pci_region; /* main I/O PCI region */ enum hw_cards_id cardtype; + int nsubdevs; struct diosubd_data sdi[MAX_DI_SUBDEVS]; /* DI chans */ struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */ struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */ @@ -256,153 +248,152 @@ struct dio_boardtype { enum hw_io_access io_access; }; -static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1730) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1733) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1753) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1754) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1756) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1760) }, - { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1762) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pci_dio_pci_table); - static const struct dio_boardtype boardtypes[] = { - {"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG, - TYPE_PCI1730, - { {16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0} }, - { {16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG, - TYPE_PCI1733, - { {0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG, - TYPE_PCI1734, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG, - TYPE_PCI1735, - { {32, PCI1735_DI, 4, 0}, {0, 0, 0, 0} }, - { {32, PCI1735_DO, 4, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { 4, PCI1735_BOARDID, 1, SDF_INTERNAL}, - { {3, PCI1735_C8254, 1, 0} }, - IO_8b}, - {"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG, - TYPE_PCI1736, - { {0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0} }, - { {0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI1736_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG, - TYPE_PCI1750, - { {0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0} }, - { {0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG, - TYPE_PCI1751, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {3, PCI1751_CNT, 1, 0} }, - IO_8b}, - {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG, - TYPE_PCI1752, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_16b}, - {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, - TYPE_PCI1753, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, - TYPE_PCI1753E, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG, - TYPE_PCI1754, - { {32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_16b}, - {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG, - TYPE_PCI1756, - { {0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0} }, - { {0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_16b}, - {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0, - TYPE_PCI1760, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, /* This card have own setup work */ - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG, - TYPE_PCI1762, - { {0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0} }, - { {0, 0, 0, 0}, {16, PCI1762_RO, 1, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI1762_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_16b} -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dio_boardtype)) - -static struct comedi_driver driver_pci_dio = { - .driver_name = "adv_pci_dio", - .module = THIS_MODULE, - .attach = pci_dio_attach, - .detach = pci_dio_detach + [TYPE_PCI1730] = { + .name = "pci1730", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1730, + .nsubdevs = 5, + .sdi[0] = { 16, PCI1730_DI, 2, 0, }, + .sdi[1] = { 16, PCI1730_IDI, 2, 0, }, + .sdo[0] = { 16, PCI1730_DO, 2, 0, }, + .sdo[1] = { 16, PCI1730_IDO, 2, 0, }, + .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_8b, + }, + [TYPE_PCI1733] = { + .name = "pci1733", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1733, + .nsubdevs = 2, + .sdi[1] = { 32, PCI1733_IDI, 4, 0, }, + .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_8b, + }, + [TYPE_PCI1734] = { + .name = "pci1734", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1734, + .nsubdevs = 2, + .sdo[1] = { 32, PCI1734_IDO, 4, 0, }, + .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_8b, + }, + [TYPE_PCI1735] = { + .name = "pci1735", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1735, + .nsubdevs = 4, + .sdi[0] = { 32, PCI1735_DI, 4, 0, }, + .sdo[0] = { 32, PCI1735_DO, 4, 0, }, + .boardid = { 4, PCI1735_BOARDID, 1, SDF_INTERNAL, }, + .s8254[0] = { 3, PCI1735_C8254, 1, 0, }, + .io_access = IO_8b, + }, + [TYPE_PCI1736] = { + .name = "pci1736", + .main_pci_region = PCI1736_MAINREG, + .cardtype = TYPE_PCI1736, + .nsubdevs = 3, + .sdi[1] = { 16, PCI1736_IDI, 2, 0, }, + .sdo[1] = { 16, PCI1736_IDO, 2, 0, }, + .boardid = { 4, PCI1736_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_8b, + }, + [TYPE_PCI1739] = { + .name = "pci1739", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1739, + .nsubdevs = 2, + .sdio[0] = { 48, PCI1739_DIO, 2, 0, }, + .io_access = IO_8b, + }, + [TYPE_PCI1750] = { + .name = "pci1750", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1750, + .nsubdevs = 2, + .sdi[1] = { 16, PCI1750_IDI, 2, 0, }, + .sdo[1] = { 16, PCI1750_IDO, 2, 0, }, + .io_access = IO_8b, + }, + [TYPE_PCI1751] = { + .name = "pci1751", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1751, + .nsubdevs = 3, + .sdio[0] = { 48, PCI1751_DIO, 2, 0, }, + .s8254[0] = { 3, PCI1751_CNT, 1, 0, }, + .io_access = IO_8b, + }, + [TYPE_PCI1752] = { + .name = "pci1752", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1752, + .nsubdevs = 3, + .sdo[0] = { 32, PCI1752_IDO, 2, 0, }, + .sdo[1] = { 32, PCI1752_IDO2, 2, 0, }, + .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_16b, + }, + [TYPE_PCI1753] = { + .name = "pci1753", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1753, + .nsubdevs = 4, + .sdio[0] = { 96, PCI1753_DIO, 4, 0, }, + .io_access = IO_8b, + }, + [TYPE_PCI1753E] = { + .name = "pci1753e", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1753E, + .nsubdevs = 8, + .sdio[0] = { 96, PCI1753_DIO, 4, 0, }, + .sdio[1] = { 96, PCI1753E_DIO, 4, 0, }, + .io_access = IO_8b, + }, + [TYPE_PCI1754] = { + .name = "pci1754", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1754, + .nsubdevs = 3, + .sdi[0] = { 32, PCI1754_IDI, 2, 0, }, + .sdi[1] = { 32, PCI1754_IDI2, 2, 0, }, + .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_16b, + }, + [TYPE_PCI1756] = { + .name = "pci1756", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1756, + .nsubdevs = 3, + .sdi[1] = { 32, PCI1756_IDI, 2, 0, }, + .sdo[1] = { 32, PCI1756_IDO, 2, 0, }, + .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_16b, + }, + [TYPE_PCI1760] = { + /* This card has its own 'attach' */ + .name = "pci1760", + .main_pci_region = 0, + .cardtype = TYPE_PCI1760, + .nsubdevs = 4, + .io_access = IO_8b, + }, + [TYPE_PCI1762] = { + .name = "pci1762", + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1762, + .nsubdevs = 3, + .sdi[1] = { 16, PCI1762_IDI, 1, 0, }, + .sdo[1] = { 16, PCI1762_RO, 1, 0, }, + .boardid = { 4, PCI1762_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_16b, + }, }; struct pci_dio_private { - struct pci_dio_private *prev; /* previous private struct */ - struct pci_dio_private *next; /* next private struct */ - struct pci_dev *pcidev; /* pointer to board's pci_dev */ char valid; /* card is usable */ char GlobalIrqEnabled; /* 1= any IRQ source is enabled */ /* PCI-1760 specific data */ @@ -422,11 +413,6 @@ struct pci_dio_private { unsigned short IDIFiltrHigh[8]; /* IDI's filter value high signal */ }; -static struct pci_dio_private *pci_priv = NULL; /* list of allocated cards */ - -#define devpriv ((struct pci_dio_private *)dev->private) -#define this_board ((const struct dio_boardtype *)dev->board_ptr) - /* ============================================================================== */ @@ -442,7 +428,7 @@ static int pci_dio_insn_bits_di_b(struct comedi_device *dev, data[1] |= inb(dev->iobase + d->addr + i) << (8 * i); - return 2; + return insn->n; } /* @@ -459,51 +445,45 @@ static int pci_dio_insn_bits_di_w(struct comedi_device *dev, for (i = 0; i < d->regs; i++) data[1] |= inw(dev->iobase + d->addr + 2 * i) << (16 * i); - return 2; + return insn->n; } -/* -============================================================================== -*/ static int pci_dio_insn_bits_do_b(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { for (i = 0; i < d->regs; i++) outb((s->state >> (8 * i)) & 0xff, dev->iobase + d->addr + i); } + data[1] = s->state; - return 2; + return insn->n; } -/* -============================================================================== -*/ static int pci_dio_insn_bits_do_w(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { const struct diosubd_data *d = (const struct diosubd_data *)s->private; int i; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { for (i = 0; i < d->regs; i++) outw((s->state >> (16 * i)) & 0xffff, dev->iobase + d->addr + 2 * i); } + data[1] = s->state; - return 2; + return insn->n; } /* @@ -652,15 +632,13 @@ static int pci1760_insn_bits_di(struct comedi_device *dev, { data[1] = inb(dev->iobase + IMB3); - return 2; + return insn->n; } -/* -============================================================================== -*/ static int pci1760_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { int ret; unsigned char omb[4] = { @@ -671,17 +649,16 @@ static int pci1760_insn_bits_do(struct comedi_device *dev, }; unsigned char imb[4]; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + if (comedi_dio_update_state(s, data)) { omb[0] = s->state; ret = pci1760_mbxrequest(dev, omb, imb); if (!ret) return ret; } + data[1] = s->state; - return 2; + return insn->n; } /* @@ -717,6 +694,7 @@ static int pci1760_insn_cnt_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci_dio_private *devpriv = dev->private; int ret; unsigned char chan = CR_CHAN(insn->chanspec) & 0x07; unsigned char bitmask = 1 << chan; @@ -759,6 +737,7 @@ static int pci1760_insn_cnt_write(struct comedi_device *dev, */ static int pci1760_reset(struct comedi_device *dev) { + struct pci_dio_private *devpriv = dev->private; int i; unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 }; unsigned char imb[4]; @@ -839,7 +818,7 @@ static int pci1760_reset(struct comedi_device *dev) */ static int pci_dio_reset(struct comedi_device *dev) { - DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n"); + const struct dio_boardtype *this_board = comedi_board(dev); switch (this_board->cardtype) { case TYPE_PCI1730: @@ -883,6 +862,11 @@ static int pci_dio_reset(struct comedi_device *dev) outb(0, dev->iobase + PCI1736_3_INT_RF); break; + case TYPE_PCI1739: + /* disable & clear interrupts */ + outb(0x88, dev->iobase + PCI1739_ICR); + break; + case TYPE_PCI1750: case TYPE_PCI1751: /* disable & clear interrupts */ @@ -935,21 +919,17 @@ static int pci_dio_reset(struct comedi_device *dev) break; } - DPRINTK("adv_pci_dio EDBG: END: pci171x_reset(...)\n"); - return 0; } /* ============================================================================== */ -static int pci1760_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci1760_attach(struct comedi_device *dev) { struct comedi_subdevice *s; - int subdev = 0; - s = dev->subdevices + subdev; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 8; @@ -957,9 +937,8 @@ static int pci1760_attach(struct comedi_device *dev, s->len_chanlist = 8; s->range_table = &range_digital; s->insn_bits = pci1760_insn_bits_di; - subdev++; - s = dev->subdevices + subdev; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 8; @@ -968,18 +947,16 @@ static int pci1760_attach(struct comedi_device *dev, s->range_table = &range_digital; s->state = 0; s->insn_bits = pci1760_insn_bits_do; - subdev++; - s = dev->subdevices + subdev; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_TIMER; s->subdev_flags = SDF_WRITABLE | SDF_LSAMPL; s->n_chan = 2; s->maxdata = 0xffffffff; s->len_chanlist = 2; /* s->insn_config=pci1760_insn_pwm_cfg; */ - subdev++; - s = dev->subdevices + subdev; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 8; @@ -988,7 +965,6 @@ static int pci1760_attach(struct comedi_device *dev, s->insn_read = pci1760_insn_cnt_read; s->insn_write = pci1760_insn_cnt_write; /* s->insn_config=pci1760_insn_cnt_cfg; */ - subdev++; return 0; } @@ -996,9 +972,12 @@ static int pci1760_attach(struct comedi_device *dev, /* ============================================================================== */ -static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s, - const struct diosubd_data *d, int subdev) +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); + s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags; if (d->chans > 16) @@ -1023,9 +1002,12 @@ static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s, /* ============================================================================== */ -static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, - const struct diosubd_data *d, int subdev) +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); + s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; if (d->chans > 16) @@ -1053,7 +1035,7 @@ static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, */ static int pci_dio_add_8254(struct comedi_device *dev, struct comedi_subdevice *s, - const struct diosubd_data *d, int subdev) + const struct diosubd_data *d) { s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; @@ -1068,164 +1050,111 @@ static int pci_dio_add_8254(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ -static int CheckAndAllocCard(struct comedi_device *dev, - struct comedi_devconfig *it, - struct pci_dev *pcidev) +static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev, + unsigned long cardtype) { - struct pci_dio_private *pr, *prev; - - for (pr = pci_priv, prev = NULL; pr != NULL; prev = pr, pr = pr->next) { - if (pr->pcidev == pcidev) - return 0; /* this card is used, look for another */ - - } - - if (prev) { - devpriv->prev = prev; - prev->next = devpriv; - } else { - pci_priv = devpriv; + /* + * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion + * board available. Need to enable PCI device and request the main + * registers PCI BAR temporarily to perform the test. + */ + if (cardtype != TYPE_PCI1753) + return cardtype; + if (pci_enable_device(pcidev) < 0) + return cardtype; + if (pci_request_region(pcidev, PCIDIO_MAINREG, "adv_pci_dio") == 0) { + /* + * This test is based on Advantech's "advdaq" driver source + * (which declares its module licence as "GPL" although the + * driver source does not include a "COPYING" file). + */ + unsigned long reg = + pci_resource_start(pcidev, PCIDIO_MAINREG) + 53; + + outb(0x05, reg); + if ((inb(reg) & 0x07) == 0x02) { + outb(0x02, reg); + if ((inb(reg) & 0x07) == 0x05) + cardtype = TYPE_PCI1753E; + } + pci_release_region(pcidev, PCIDIO_MAINREG); } - - devpriv->pcidev = pcidev; - - return 1; + pci_disable_device(pcidev); + return cardtype; } -/* -============================================================================== -*/ -static int pci_dio_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci_dio_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct dio_boardtype *this_board = NULL; + struct pci_dio_private *devpriv; struct comedi_subdevice *s; - int ret, subdev, n_subdevices, i, j; - unsigned long iobase; - struct pci_dev *pcidev = NULL; - - printk("comedi%d: adv_pci_dio: ", dev->minor); - - ret = alloc_private(dev, sizeof(struct pci_dio_private)); - if (ret < 0) { - printk(", Error: Cann't allocate private memory!\n"); - return -ENOMEM; - } - - for_each_pci_dev(pcidev) { - /* loop through cards supported by this driver */ - for (i = 0; i < n_boardtypes; ++i) { - if (boardtypes[i].vendor_id != pcidev->vendor) - continue; - if (boardtypes[i].device_id != pcidev->device) - continue; - /* was a particular bus/slot requested? */ - if (it->options[0] || it->options[1]) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - ret = CheckAndAllocCard(dev, it, pcidev); - if (ret != 1) - continue; - dev->board_ptr = boardtypes + i; - break; - } - if (dev->board_ptr) - break; - } - - if (!dev->board_ptr) { - printk(", Error: Requested type of the card was not found!\n"); - return -EIO; - } + int ret, subdev, i, j; - if (comedi_pci_enable(pcidev, driver_pci_dio.driver_name)) { - printk - (", Error: Can't enable PCI device and request regions!\n"); - return -EIO; - } - iobase = pci_resource_start(pcidev, this_board->main_pci_region); - printk(", b:s:f=%d:%d:%d, io=0x%4lx", - pcidev->bus->number, PCI_SLOT(pcidev->devfn), - PCI_FUNC(pcidev->devfn), iobase); - - dev->iobase = iobase; + if (context < ARRAY_SIZE(boardtypes)) + this_board = &boardtypes[context]; + if (!this_board) + return -ENODEV; + dev->board_ptr = this_board; dev->board_name = this_board->name; - if (this_board->cardtype == TYPE_PCI1760) { - n_subdevices = 4; /* 8 IDI, 8 IDO, 2 PWM, 8 CNT */ - } else { - n_subdevices = 0; - for (i = 0; i < MAX_DI_SUBDEVS; i++) - if (this_board->sdi[i].chans) - n_subdevices++; - for (i = 0; i < MAX_DO_SUBDEVS; i++) - if (this_board->sdo[i].chans) - n_subdevices++; - for (i = 0; i < MAX_DIO_SUBDEVG; i++) - n_subdevices += this_board->sdio[i].regs; - if (this_board->boardid.chans) - n_subdevices++; - for (i = 0; i < MAX_8254_SUBDEVS; i++) - if (this_board->s8254[i].chans) - n_subdevices++; - } + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) { - printk(", Error: Cann't allocate subdevice memory!\n"); + ret = comedi_pci_enable(dev); + if (ret) return ret; - } + dev->iobase = pci_resource_start(pcidev, this_board->main_pci_region); - printk(".\n"); + ret = comedi_alloc_subdevices(dev, this_board->nsubdevs); + if (ret) + return ret; subdev = 0; - for (i = 0; i < MAX_DI_SUBDEVS; i++) if (this_board->sdi[i].chans) { - s = dev->subdevices + subdev; - pci_dio_add_di(dev, s, &this_board->sdi[i], subdev); + s = &dev->subdevices[subdev]; + pci_dio_add_di(dev, s, &this_board->sdi[i]); subdev++; } for (i = 0; i < MAX_DO_SUBDEVS; i++) if (this_board->sdo[i].chans) { - s = dev->subdevices + subdev; - pci_dio_add_do(dev, s, &this_board->sdo[i], subdev); + s = &dev->subdevices[subdev]; + pci_dio_add_do(dev, s, &this_board->sdo[i]); subdev++; } for (i = 0; i < MAX_DIO_SUBDEVG; i++) for (j = 0; j < this_board->sdio[i].regs; j++) { - s = dev->subdevices + subdev; - subdev_8255_init(dev, s, NULL, - dev->iobase + - this_board->sdio[i].addr + - SIZE_8255 * j); + s = &dev->subdevices[subdev]; + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + + this_board->sdio[i].addr + + SIZE_8255 * j); + if (ret) + return ret; subdev++; } if (this_board->boardid.chans) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DI; - pci_dio_add_di(dev, s, &this_board->boardid, subdev); + pci_dio_add_di(dev, s, &this_board->boardid); subdev++; } for (i = 0; i < MAX_8254_SUBDEVS; i++) if (this_board->s8254[i].chans) { - s = dev->subdevices + subdev; - pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev); + s = &dev->subdevices[subdev]; + pci_dio_add_8254(dev, s, &this_board->s8254[i]); subdev++; } if (this_board->cardtype == TYPE_PCI1760) - pci1760_attach(dev, it); + pci1760_attach(dev); devpriv->valid = 1; @@ -1234,116 +1163,59 @@ static int pci_dio_attach(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ -static int pci_dio_detach(struct comedi_device *dev) +static void pci_dio_detach(struct comedi_device *dev) { - int i, j; - struct comedi_subdevice *s; - int subdev; + struct pci_dio_private *devpriv = dev->private; - if (dev->private) { + if (devpriv) { if (devpriv->valid) pci_dio_reset(dev); - - - /* This shows the silliness of using this kind of - * scheme for numbering subdevices. Don't do it. --ds */ - subdev = 0; - for (i = 0; i < MAX_DI_SUBDEVS; i++) { - if (this_board->sdi[i].chans) - subdev++; - - } - for (i = 0; i < MAX_DO_SUBDEVS; i++) { - if (this_board->sdo[i].chans) - subdev++; - - } - for (i = 0; i < MAX_DIO_SUBDEVG; i++) { - for (j = 0; j < this_board->sdio[i].regs; j++) { - s = dev->subdevices + subdev; - subdev_8255_cleanup(dev, s); - subdev++; - } - } - - if (this_board->boardid.chans) - subdev++; - - for (i = 0; i < MAX_8254_SUBDEVS; i++) - if (this_board->s8254[i].chans) - subdev++; - - for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; - s->private = NULL; - } - - if (devpriv->pcidev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pcidev); - - pci_dev_put(devpriv->pcidev); - } - - if (devpriv->prev) - devpriv->prev->next = devpriv->next; - else - pci_priv = devpriv->next; - - if (devpriv->next) - devpriv->next->prev = devpriv->prev; - } - - return 0; -} - -/* -============================================================================== -*/ -static int __devinit driver_pci_dio_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_pci_dio.driver_name); + comedi_pci_disable(dev); } -static void __devexit driver_pci_dio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_pci_dio_pci_driver = { - .id_table = pci_dio_pci_table, - .probe = &driver_pci_dio_pci_probe, - .remove = __devexit_p(&driver_pci_dio_pci_remove) +static struct comedi_driver adv_pci_dio_driver = { + .driver_name = "adv_pci_dio", + .module = THIS_MODULE, + .auto_attach = pci_dio_auto_attach, + .detach = pci_dio_detach, }; -static int __init driver_pci_dio_init_module(void) +static int adv_pci_dio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_pci_dio); - if (retval < 0) - return retval; + unsigned long cardtype; - driver_pci_dio_pci_driver.name = (char *)driver_pci_dio.driver_name; - return pci_register_driver(&driver_pci_dio_pci_driver); + cardtype = pci_dio_override_cardtype(dev, id->driver_data); + return comedi_pci_auto_config(dev, &adv_pci_dio_driver, cardtype); } -static void __exit driver_pci_dio_cleanup_module(void) -{ - pci_unregister_driver(&driver_pci_dio_pci_driver); - comedi_driver_unregister(&driver_pci_dio); -} +static const struct pci_device_id adv_pci_dio_pci_table[] = { + { PCI_VDEVICE(ADVANTECH, 0x1730), TYPE_PCI1730 }, + { PCI_VDEVICE(ADVANTECH, 0x1733), TYPE_PCI1733 }, + { PCI_VDEVICE(ADVANTECH, 0x1734), TYPE_PCI1734 }, + { PCI_VDEVICE(ADVANTECH, 0x1735), TYPE_PCI1735 }, + { PCI_VDEVICE(ADVANTECH, 0x1736), TYPE_PCI1736 }, + { PCI_VDEVICE(ADVANTECH, 0x1739), TYPE_PCI1739 }, + { PCI_VDEVICE(ADVANTECH, 0x1750), TYPE_PCI1750 }, + { PCI_VDEVICE(ADVANTECH, 0x1751), TYPE_PCI1751 }, + { PCI_VDEVICE(ADVANTECH, 0x1752), TYPE_PCI1752 }, + { PCI_VDEVICE(ADVANTECH, 0x1753), TYPE_PCI1753 }, + { PCI_VDEVICE(ADVANTECH, 0x1754), TYPE_PCI1754 }, + { PCI_VDEVICE(ADVANTECH, 0x1756), TYPE_PCI1756 }, + { PCI_VDEVICE(ADVANTECH, 0x1760), TYPE_PCI1760 }, + { PCI_VDEVICE(ADVANTECH, 0x1762), TYPE_PCI1762 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table); -module_init(driver_pci_dio_init_module); -module_exit(driver_pci_dio_cleanup_module); -/* -============================================================================== -*/ +static struct pci_driver adv_pci_dio_pci_driver = { + .name = "adv_pci_dio", + .id_table = adv_pci_dio_pci_table, + .probe = adv_pci_dio_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index b0f98e5e4bf..324746b1493 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -25,8 +21,9 @@ Driver: aio_aio12_8 Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board Author: Pablo Mejia <pablo.mejia@cctechnol.com> -Devices: - [Access I/O] PC-104 AIO12-8 +Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8) + [Access I/O] PC-104 AI12-8 (aio_ai12_8) + [Access I/O] PC-104 AO12-8 (aio_ao12_8) Status: experimental Configuration Options: @@ -38,97 +35,128 @@ Notes: */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include "8255.h" -#define AIO12_8_STATUS 0x00 -#define AIO12_8_INTERRUPT 0x01 -#define AIO12_8_ADC 0x02 -#define AIO12_8_DAC_0 0x04 -#define AIO12_8_DAC_1 0x06 -#define AIO12_8_DAC_2 0x08 -#define AIO12_8_DAC_3 0x0A -#define AIO12_8_COUNTER_0 0x0C -#define AIO12_8_COUNTER_1 0x0D -#define AIO12_8_COUNTER_2 0x0E -#define AIO12_8_COUNTER_CONTROL 0x0F -#define AIO12_8_DIO_0 0x10 -#define AIO12_8_DIO_1 0x11 -#define AIO12_8_DIO_2 0x12 -#define AIO12_8_DIO_STATUS 0x13 -#define AIO12_8_DIO_CONTROL 0x14 -#define AIO12_8_ADC_TRIGGER_CONTROL 0x15 -#define AIO12_8_TRIGGER 0x16 -#define AIO12_8_POWER 0x17 - -#define STATUS_ADC_EOC 0x80 - -#define ADC_MODE_NORMAL 0x00 -#define ADC_MODE_INTERNAL_CLOCK 0x40 -#define ADC_MODE_STANDBY 0x80 -#define ADC_MODE_POWERDOWN 0xC0 - -#define DAC_ENABLE 0x18 +/* + * Register map + */ +#define AIO12_8_STATUS_REG 0x00 +#define AIO12_8_STATUS_ADC_EOC (1 << 7) +#define AIO12_8_STATUS_PORT_C_COS (1 << 6) +#define AIO12_8_STATUS_IRQ_ENA (1 << 2) +#define AIO12_8_INTERRUPT_REG 0x01 +#define AIO12_8_INTERRUPT_ADC (1 << 7) +#define AIO12_8_INTERRUPT_COS (1 << 6) +#define AIO12_8_INTERRUPT_COUNTER1 (1 << 5) +#define AIO12_8_INTERRUPT_PORT_C3 (1 << 4) +#define AIO12_8_INTERRUPT_PORT_C0 (1 << 3) +#define AIO12_8_INTERRUPT_ENA (1 << 2) +#define AIO12_8_ADC_REG 0x02 +#define AIO12_8_ADC_MODE_NORMAL (0 << 6) +#define AIO12_8_ADC_MODE_INT_CLK (1 << 6) +#define AIO12_8_ADC_MODE_STANDBY (2 << 6) +#define AIO12_8_ADC_MODE_POWERDOWN (3 << 6) +#define AIO12_8_ADC_ACQ_3USEC (0 << 5) +#define AIO12_8_ADC_ACQ_PROGRAM (1 << 5) +#define AIO12_8_ADC_RANGE(x) ((x) << 3) +#define AIO12_8_ADC_CHAN(x) ((x) << 0) +#define AIO12_8_DAC_REG(x) (0x04 + (x) * 2) +#define AIO12_8_8254_BASE_REG 0x0c +#define AIO12_8_8255_BASE_REG 0x10 +#define AIO12_8_DIO_CONTROL_REG 0x14 +#define AIO12_8_DIO_CONTROL_TST (1 << 0) +#define AIO12_8_ADC_TRIGGER_REG 0x15 +#define AIO12_8_ADC_TRIGGER_RANGE(x) ((x) << 3) +#define AIO12_8_ADC_TRIGGER_CHAN(x) ((x) << 0) +#define AIO12_8_TRIGGER_REG 0x16 +#define AIO12_8_TRIGGER_ADTRIG (1 << 1) +#define AIO12_8_TRIGGER_DACTRIG (1 << 0) +#define AIO12_8_COS_REG 0x17 +#define AIO12_8_DAC_ENABLE_REG 0x18 +#define AIO12_8_DAC_ENABLE_REF_ENA (1 << 0) struct aio12_8_boardtype { const char *name; + int ai_nchan; + int ao_nchan; }; static const struct aio12_8_boardtype board_types[] = { { - .name = "aio_aio12_8"}, + .name = "aio_aio12_8", + .ai_nchan = 8, + .ao_nchan = 4, + }, { + .name = "aio_ai12_8", + .ai_nchan = 8, + }, { + .name = "aio_ao12_8", + .ao_nchan = 4, + }, }; -#define thisboard ((const struct aio12_8_boardtype *) dev->board_ptr) - struct aio12_8_private { unsigned int ao_readback[4]; }; -#define devpriv ((struct aio12_8_private *) dev->private) +static int aio_aio12_8_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + AIO12_8_STATUS_REG); + if (status & AIO12_8_STATUS_ADC_EOC) + return 0; + return -EBUSY; +} static int aio_aio12_8_ai_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned char control; + int ret; int n; - unsigned char control = - ADC_MODE_NORMAL | - (CR_RANGE(insn->chanspec) << 3) | CR_CHAN(insn->chanspec); - /* read status to clear EOC latch */ - inb(dev->iobase + AIO12_8_STATUS); + /* + * Setup the control byte for internal 2MHz clock, 3uS conversion, + * at the desired range of the requested channel. + */ + control = AIO12_8_ADC_MODE_NORMAL | AIO12_8_ADC_ACQ_3USEC | + AIO12_8_ADC_RANGE(range) | AIO12_8_ADC_CHAN(chan); - for (n = 0; n < insn->n; n++) { - int timeout = 5; + /* Read status to clear EOC latch */ + inb(dev->iobase + AIO12_8_STATUS_REG); + for (n = 0; n < insn->n; n++) { /* Setup and start conversion */ - outb(control, dev->iobase + AIO12_8_ADC); + outb(control, dev->iobase + AIO12_8_ADC_REG); /* Wait for conversion to complete */ - while (timeout && - !(inb(dev->iobase + AIO12_8_STATUS) & STATUS_ADC_EOC)) { - timeout--; - printk(KERN_ERR "timeout %d\n", timeout); - udelay(1); - } - if (timeout == 0) { - comedi_error(dev, "ADC timeout"); - return -EIO; - } - - data[n] = inw(dev->iobase + AIO12_8_ADC) & 0x0FFF; + ret = comedi_timeout(dev, s, insn, aio_aio12_8_ai_eoc, 0); + if (ret) + return ret; + + data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; } - return n; + + 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; - int val = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; for (i = 0; i < insn->n; i++) data[i] = val; @@ -139,106 +167,105 @@ static int aio_aio12_8_ao_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; int i; - int chan = CR_CHAN(insn->chanspec); - unsigned long port = dev->iobase + AIO12_8_DAC_0 + (2 * chan); /* enable DACs */ - outb(0x01, dev->iobase + DAC_ENABLE); + outb(AIO12_8_DAC_ENABLE_REF_ENA, dev->iobase + AIO12_8_DAC_ENABLE_REG); for (i = 0; i < insn->n; i++) { - outb(data[i] & 0xFF, port); /* LSB */ - outb((data[i] >> 8) & 0x0F, port + 1); /* MSB */ - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + outw(val, port); } + + devpriv->ao_readback[chan] = val; + return insn->n; } static const struct comedi_lrange range_aio_aio12_8 = { - 4, - { - UNI_RANGE(5), - BIP_RANGE(5), - UNI_RANGE(10), - BIP_RANGE(10), - } + 4, { + UNI_RANGE(5), + BIP_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(10) + } }; static int aio_aio12_8_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int iobase; + const struct aio12_8_boardtype *board = comedi_board(dev); + struct aio12_8_private *devpriv; struct comedi_subdevice *s; + int ret; - iobase = it->options[0]; - if (!request_region(iobase, 24, "aio_aio12_8")) { - printk(KERN_ERR "I/O port conflict"); - return -EIO; - } + ret = comedi_request_region(dev, it->options[0], 32); + if (ret) + return ret; - dev->board_name = thisboard->name; - - dev->iobase = iobase; - - if (alloc_private(dev, sizeof(struct aio12_8_private)) < 0) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = 8; - s->maxdata = (1 << 12) - 1; - s->range_table = &range_aio_aio12_8; - s->insn_read = aio_aio12_8_ai_read; + if (board->ai_nchan) { + /* Analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = board->ai_nchan; + s->maxdata = 0x0fff; + s->range_table = &range_aio_aio12_8; + s->insn_read = aio_aio12_8_ai_read; + } else { + s->type = COMEDI_SUBD_UNUSED; + } s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = 4; - s->maxdata = (1 << 12) - 1; - s->range_table = &range_aio_aio12_8; - s->insn_read = aio_aio12_8_ao_read; - s->insn_write = aio_aio12_8_ao_write; + if (board->ao_nchan) { + /* Analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF; + 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; + } else { + s->type = COMEDI_SUBD_UNUSED; + } s = &dev->subdevices[2]; - subdev_8255_init(dev, s, NULL, dev->iobase + AIO12_8_DIO_0); + /* 8255 Digital i/o subdevice */ + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + AIO12_8_8255_BASE_REG); + if (ret) + return ret; - return 0; -} + s = &dev->subdevices[3]; + /* 8254 counter/timer subdevice */ + s->type = COMEDI_SUBD_UNUSED; -static int aio_aio12_8_detach(struct comedi_device *dev) -{ - subdev_8255_cleanup(dev, &dev->subdevices[2]); - if (dev->iobase) - release_region(dev->iobase, 24); return 0; } -static struct comedi_driver driver_aio_aio12_8 = { - .driver_name = "aio_aio12_8", - .module = THIS_MODULE, - .attach = aio_aio12_8_attach, - .detach = aio_aio12_8_detach, - .board_name = &board_types[0].name, - .num_names = 1, - .offset = sizeof(struct aio12_8_boardtype), +static struct comedi_driver aio_aio12_8_driver = { + .driver_name = "aio_aio12_8", + .module = THIS_MODULE, + .attach = aio_aio12_8_attach, + .detach = comedi_legacy_detach, + .board_name = &board_types[0].name, + .num_names = ARRAY_SIZE(board_types), + .offset = sizeof(struct aio12_8_boardtype), }; - -static int __init driver_aio_aio12_8_init_module(void) -{ - return comedi_driver_register(&driver_aio_aio12_8); -} - -static void __exit driver_aio_aio12_8_cleanup_module(void) -{ - comedi_driver_unregister(&driver_aio_aio12_8); -} - -module_init(driver_aio_aio12_8_init_module); -module_exit(driver_aio_aio12_8_cleanup_module); +module_comedi_driver(aio_aio12_8_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index 160b0a0f4f1..781104aa533 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -34,8 +30,8 @@ Configuration Options: */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #define AIO_IIRO_16_SIZE 0x08 #define AIO_IIRO_16_RELAY_0_7 0x00 @@ -44,80 +40,49 @@ Configuration Options: #define AIO_IIRO_16_RELAY_8_15 0x04 #define AIO_IIRO_16_INPUT_8_15 0x05 -struct aio_iiro_16_board { - const char *name; - int do_; - int di; -}; - -static const struct aio_iiro_16_board aio_iiro_16_boards[] = { - { - .name = "aio_iiro_16", - .di = 16, - .do_ = 16}, -}; - -#define thisboard ((const struct aio_iiro_16_board *) dev->board_ptr) - -struct aio_iiro_16_private { - int data; - struct pci_dev *pci_dev; - unsigned int ao_readback[2]; -}; +static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7); + outb((s->state >> 8) & 0xff, + dev->iobase + AIO_IIRO_16_RELAY_8_15); + } -#define devpriv ((struct aio_iiro_16_private *) dev->private) + data[1] = s->state; -static int aio_iiro_16_attach(struct comedi_device *dev, - struct comedi_devconfig *it); - -static int aio_iiro_16_detach(struct comedi_device *dev); - -static struct comedi_driver driver_aio_iiro_16 = { - .driver_name = "aio_iiro_16", - .module = THIS_MODULE, - .attach = aio_iiro_16_attach, - .detach = aio_iiro_16_detach, - .board_name = &aio_iiro_16_boards[0].name, - .offset = sizeof(struct aio_iiro_16_board), - .num_names = ARRAY_SIZE(aio_iiro_16_boards), -}; + return insn->n; +} static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); + unsigned int *data) +{ + data[1] = 0; + data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7); + data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8; -static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + return insn->n; +} static int aio_iiro_16_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int iobase; struct comedi_subdevice *s; + int ret; - printk(KERN_INFO "comedi%d: aio_iiro_16: ", dev->minor); + ret = comedi_request_region(dev, it->options[0], AIO_IIRO_16_SIZE); + if (ret) + return ret; - dev->board_name = thisboard->name; + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; - iobase = it->options[0]; - - if (!request_region(iobase, AIO_IIRO_16_SIZE, dev->board_name)) { - printk("I/O port conflict"); - return -EIO; - } - - dev->iobase = iobase; - - if (alloc_private(dev, sizeof(struct aio_iiro_16_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 16; @@ -125,7 +90,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = aio_iiro_16_dio_insn_bits_write; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE; s->n_chan = 16; @@ -133,69 +98,16 @@ static int aio_iiro_16_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = aio_iiro_16_dio_insn_bits_read; - printk("attached\n"); - - return 1; -} - -static int aio_iiro_16_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: aio_iiro_16: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, AIO_IIRO_16_SIZE); - return 0; } -static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7); - outb((s->state >> 8) & 0xff, - dev->iobase + AIO_IIRO_16_RELAY_8_15); - } - - data[1] = s->state; - - return 2; -} - -static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = 0; - data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7); - data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8; - - return 2; -} - -static int __init driver_aio_iiro_16_init_module(void) -{ - return comedi_driver_register(&driver_aio_iiro_16); -} - -static void __exit driver_aio_iiro_16_cleanup_module(void) -{ - comedi_driver_unregister(&driver_aio_iiro_16); -} - -module_init(driver_aio_iiro_16_init_module); -module_exit(driver_aio_iiro_16_cleanup_module); +static struct comedi_driver aio_iiro_16_driver = { + .driver_name = "aio_iiro_16", + .module = THIS_MODULE, + .attach = aio_iiro_16_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(aio_iiro_16_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/am9513.h b/drivers/staging/comedi/drivers/am9513.h deleted file mode 100644 index 0bb839e5149..00000000000 --- a/drivers/staging/comedi/drivers/am9513.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - module/am9513.h - value added preprocessor definitions for Am9513 timer chip - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef _AM9513_H_ -#define _AM9513_H_ - -#if 0 - -/* - * Before including this file, the following need to be defined: - */ -#define Am9513_8BITBUS xxx -/* or */ -#define Am9513_16BITBUS xxx - -#define Am9513_output_control(a) xxx -#define Am9513_input_status() xxx -#define Am9513_output_data(a) xxx -#define Am9513_input_data() xxx - -#endif - -/* - * - */ - -#ifdef Am9513_8BITBUS - -#define Am9513_write_register(reg, val) \ - do { \ - Am9513_output_control(reg); \ - Am9513_output_data(val>>8); \ - Am9513_output_data(val&0xff); \ - } while (0) - -#define Am9513_read_register(reg, val) \ - do { \ - Am9513_output_control(reg); \ - val = Am9513_input_data()<<8; \ - val |= Am9513_input_data(); \ - } while (0) - -#else /* Am9513_16BITBUS */ - -#define Am9513_write_register(reg, val) \ - do { \ - Am9513_output_control(reg); \ - Am9513_output_data(val); \ - } while (0) - -#define Am9513_read_register(reg, val) \ - do { \ - Am9513_output_control(reg); \ - val = Am9513_input_data(); \ - } while (0) - -#endif - -#endif diff --git a/drivers/staging/comedi/drivers/amcc_s5933.h b/drivers/staging/comedi/drivers/amcc_s5933.h index b810d5f3d97..2ba73644461 100644 --- a/drivers/staging/comedi/drivers/amcc_s5933.h +++ b/drivers/staging/comedi/drivers/amcc_s5933.h @@ -145,12 +145,12 @@ #define AINT_READ_COMPL 0x00008000 #define AINT_WRITE_COMPL 0x00004000 -#define AINT_OMB_ENABLE 0x00001000 -#define AINT_OMB_SELECT 0x00000c00 +#define AINT_OMB_ENABLE 0x00001000 +#define AINT_OMB_SELECT 0x00000c00 #define AINT_OMB_BYTE 0x00000300 -#define AINT_IMB_ENABLE 0x00000010 -#define AINT_IMB_SELECT 0x0000000c +#define AINT_IMB_ENABLE 0x00000010 +#define AINT_IMB_SELECT 0x0000000c #define AINT_IMB_BYTE 0x00000003 /* these are bits from various different registers, needs cleanup XXX */ diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index 93bbe4ec318..dc1dee79fc1 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -1,10 +1,9 @@ /* comedi/drivers/amplc_dio200.c - Driver for Amplicon PC272E and PCI272 DIO boards. - (Support for other boards in Amplicon 200 series may be added at - a later date, e.g. PCI215.) - Copyright (C) 2005 MEV Ltd. <http://www.mev.co.uk/> + Driver for Amplicon PC212E, PC214E, PC215E, PC218E, PC272E. + + Copyright (C) 2005-2013 MEV Ltd. <http://www.mev.co.uk/> COMEDI - Linux Control and Measurement Device Interface Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org> @@ -18,1539 +17,289 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* -Driver: amplc_dio200 -Description: Amplicon 200 Series Digital I/O -Author: Ian Abbott <abbotti@mev.co.uk> -Devices: [Amplicon] PC212E (pc212e), PC214E (pc214e), PC215E (pc215e), - PCI215 (pci215 or amplc_dio200), PC218E (pc218e), PC272E (pc272e), - PCI272 (pci272 or amplc_dio200) -Updated: Wed, 22 Oct 2008 13:36:02 +0100 -Status: works - -Configuration options - PC212E, PC214E, PC215E, PC218E, PC272E: - [0] - I/O port base address - [1] - IRQ (optional, but commands won't work without it) - -Configuration options - PCI215, PCI272: - [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. - -Passing a zero for an option is the same as leaving it unspecified. - -SUBDEVICES - - PC218E PC212E PC215E/PCI215 - ------------- ------------- ------------- - Subdevices 7 6 5 - 0 CTR-X1 PPI-X PPI-X - 1 CTR-X2 CTR-Y1 PPI-Y - 2 CTR-Y1 CTR-Y2 CTR-Z1 - 3 CTR-Y2 CTR-Z1 CTR-Z2 - 4 CTR-Z1 CTR-Z2 INTERRUPT - 5 CTR-Z2 INTERRUPT - 6 INTERRUPT - - PC214E PC272E/PCI272 - ------------- ------------- - Subdevices 4 4 - 0 PPI-X PPI-X - 1 PPI-Y PPI-Y - 2 CTR-Z1* PPI-Z - 3 INTERRUPT* INTERRUPT - -Each PPI is a 8255 chip providing 24 DIO channels. The DIO channels -are configurable as inputs or outputs in four groups: - - Port A - channels 0 to 7 - Port B - channels 8 to 15 - Port CL - channels 16 to 19 - Port CH - channels 20 to 23 - -Only mode 0 of the 8255 chips is supported. - -Each CTR is a 8254 chip providing 3 16-bit counter channels. Each -channel is configured individually with INSN_CONFIG instructions. The -specific type of configuration instruction is specified in data[0]. -Some configuration instructions expect an additional parameter in -data[1]; others return a value in data[1]. The following configuration -instructions are supported: - - INSN_CONFIG_SET_COUNTER_MODE. Sets the counter channel's mode and - BCD/binary setting specified in data[1]. - - INSN_CONFIG_8254_READ_STATUS. Reads the status register value for the - counter channel into data[1]. - - INSN_CONFIG_SET_CLOCK_SRC. Sets the counter channel's clock source as - specified in data[1] (this is a hardware-specific value). Not - supported on PC214E. For the other boards, valid clock sources are - 0 to 7 as follows: - - 0. CLK n, the counter channel's dedicated CLK input from the SK1 - connector. (N.B. for other values, the counter channel's CLKn - pin on the SK1 connector is an output!) - 1. Internal 10 MHz clock. - 2. Internal 1 MHz clock. - 3. Internal 100 kHz clock. - 4. Internal 10 kHz clock. - 5. Internal 1 kHz clock. - 6. OUT n-1, the output of counter channel n-1 (see note 1 below). - 7. Ext Clock, the counter chip's dedicated Ext Clock input from - the SK1 connector. This pin is shared by all three counter - channels on the chip. - - INSN_CONFIG_GET_CLOCK_SRC. Returns the counter channel's current - clock source in data[1]. For internal clock sources, data[2] is set - to the period in ns. - - INSN_CONFIG_SET_GATE_SRC. Sets the counter channel's gate source as - specified in data[2] (this is a hardware-specific value). Not - supported on PC214E. For the other boards, valid gate sources are 0 - to 7 as follows: - - 0. VCC (internal +5V d.c.), i.e. gate permanently enabled. - 1. GND (internal 0V d.c.), i.e. gate permanently disabled. - 2. GAT n, the counter channel's dedicated GAT input from the SK1 - connector. (N.B. for other values, the counter channel's GATn - pin on the SK1 connector is an output!) - 3. /OUT n-2, the inverted output of counter channel n-2 (see note - 2 below). - 4. Reserved. - 5. Reserved. - 6. Reserved. - 7. Reserved. - - INSN_CONFIG_GET_GATE_SRC. Returns the counter channel's current gate - source in data[2]. - -Clock and gate interconnection notes: - - 1. Clock source OUT n-1 is the output of the preceding channel on the - same counter subdevice if n > 0, or the output of channel 2 on the - preceding counter subdevice (see note 3) if n = 0. - - 2. Gate source /OUT n-2 is the inverted output of channel 0 on the - same counter subdevice if n = 2, or the inverted output of channel n+1 - on the preceding counter subdevice (see note 3) if n < 2. - - 3. The counter subdevices are connected in a ring, so the highest - counter subdevice precedes the lowest. - -The 'INTERRUPT' subdevice pretends to be a digital input subdevice. The -digital inputs come from the interrupt status register. The number of -channels matches the number of interrupt sources. The PC214E does not -have an interrupt status register; see notes on 'INTERRUPT SOURCES' -below. - -INTERRUPT SOURCES - - PC218E PC212E PC215E/PCI215 - ------------- ------------- ------------- - Sources 6 6 6 - 0 CTR-X1-OUT PPI-X-C0 PPI-X-C0 - 1 CTR-X2-OUT PPI-X-C3 PPI-X-C3 - 2 CTR-Y1-OUT CTR-Y1-OUT PPI-Y-C0 - 3 CTR-Y2-OUT CTR-Y2-OUT PPI-Y-C3 - 4 CTR-Z1-OUT CTR-Z1-OUT CTR-Z1-OUT - 5 CTR-Z2-OUT CTR-Z2-OUT CTR-Z2-OUT - - PC214E PC272E/PCI272 - ------------- ------------- - Sources 1 6 - 0 JUMPER-J5 PPI-X-C0 - 1 PPI-X-C3 - 2 PPI-Y-C0 - 3 PPI-Y-C3 - 4 PPI-Z-C0 - 5 PPI-Z-C3 - -When an interrupt source is enabled in the interrupt source enable -register, a rising edge on the source signal latches the corresponding -bit to 1 in the interrupt status register. - -When the interrupt status register value as a whole (actually, just the -6 least significant bits) goes from zero to non-zero, the board will -generate an interrupt. For level-triggered hardware interrupts (PCI -card), the interrupt will remain asserted until the interrupt status -register is cleared to zero. For edge-triggered hardware interrupts -(ISA card), no further interrupts will occur until the interrupt status -register is cleared to zero. To clear a bit to zero in the interrupt -status register, the corresponding interrupt source must be disabled -in the interrupt source enable register (there is no separate interrupt -clear register). - -The PC214E does not have an interrupt source enable register or an -interrupt status register; its 'INTERRUPT' subdevice has a single -channel and its interrupt source is selected by the position of jumper -J5. - -COMMANDS - -The driver supports a read streaming acquisition command on the -'INTERRUPT' subdevice. The channel list selects the interrupt sources -to be enabled. All channels will be sampled together (convert_src == -TRIG_NOW). The scan begins a short time after the hardware interrupt -occurs, subject to interrupt latencies (scan_begin_src == TRIG_EXT, -scan_begin_arg == 0). The value read from the interrupt status register -is packed into a short value, one bit per requested channel, in the -order they appear in the channel list. -*/ - -#include <linux/interrupt.h> -#include <linux/slab.h> - -#include "../comedidev.h" - -#include "comedi_pci.h" - -#include "8255.h" -#include "8253.h" - -#define DIO200_DRIVER_NAME "amplc_dio200" - -/* PCI IDs */ -#define PCI_VENDOR_ID_AMPLICON 0x14dc -#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a -#define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b -#define PCI_DEVICE_ID_INVALID 0xffff - -/* 200 series registers */ -#define DIO200_IO_SIZE 0x20 -#define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */ -#define DIO200_YCLK_SCE 0x19 /* Group Y clock selection register */ -#define DIO200_ZCLK_SCE 0x1a /* Group Z clock selection register */ -#define DIO200_XGAT_SCE 0x1b /* Group X gate selection register */ -#define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */ -#define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */ -#define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */ - -/* - * Macros for constructing value for DIO_200_?CLK_SCE and - * DIO_200_?GAT_SCE registers: + * Driver: amplc_dio200 + * Description: Amplicon 200 Series ISA Digital I/O + * Author: Ian Abbott <abbotti@mev.co.uk> + * Devices: [Amplicon] PC212E (pc212e), PC214E (pc214e), PC215E (pc215e), + * PC218E (pc218e), PC272E (pc272e) + * Updated: Mon, 18 Mar 2013 14:40:41 +0000 + * + * Status: works + * + * Configuration options: + * [0] - I/O port base address + * [1] - IRQ (optional, but commands won't work without it) * - * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2. - * 'chan' is the channel: 0, 1 or 2. - * 'source' is the signal source: 0 to 7. + * Passing a zero for an option is the same as leaving it unspecified. + * + * SUBDEVICES + * + * PC212E PC214E PC215E + * ------------- ------------- ------------- + * Subdevices 6 4 5 + * 0 PPI-X PPI-X PPI-X + * 1 CTR-Y1 PPI-Y PPI-Y + * 2 CTR-Y2 CTR-Z1* CTR-Z1 + * 3 CTR-Z1 INTERRUPT* CTR-Z2 + * 4 CTR-Z2 INTERRUPT + * 5 INTERRUPT + * + * PC218E PC272E + * ------------- ------------- + * Subdevices 7 4 + * 0 CTR-X1 PPI-X + * 1 CTR-X2 PPI-Y + * 2 CTR-Y1 PPI-Z + * 3 CTR-Y2 INTERRUPT + * 4 CTR-Z1 + * 5 CTR-Z2 + * 6 INTERRUPT + * + * Each PPI is a 8255 chip providing 24 DIO channels. The DIO channels + * are configurable as inputs or outputs in four groups: + * + * Port A - channels 0 to 7 + * Port B - channels 8 to 15 + * Port CL - channels 16 to 19 + * Port CH - channels 20 to 23 + * + * Only mode 0 of the 8255 chips is supported. + * + * Each CTR is a 8254 chip providing 3 16-bit counter channels. Each + * channel is configured individually with INSN_CONFIG instructions. The + * specific type of configuration instruction is specified in data[0]. + * Some configuration instructions expect an additional parameter in + * data[1]; others return a value in data[1]. The following configuration + * instructions are supported: + * + * INSN_CONFIG_SET_COUNTER_MODE. Sets the counter channel's mode and + * BCD/binary setting specified in data[1]. + * + * INSN_CONFIG_8254_READ_STATUS. Reads the status register value for the + * counter channel into data[1]. + * + * INSN_CONFIG_SET_CLOCK_SRC. Sets the counter channel's clock source as + * specified in data[1] (this is a hardware-specific value). Not + * supported on PC214E. For the other boards, valid clock sources are + * 0 to 7 as follows: + * + * 0. CLK n, the counter channel's dedicated CLK input from the SK1 + * connector. (N.B. for other values, the counter channel's CLKn + * pin on the SK1 connector is an output!) + * 1. Internal 10 MHz clock. + * 2. Internal 1 MHz clock. + * 3. Internal 100 kHz clock. + * 4. Internal 10 kHz clock. + * 5. Internal 1 kHz clock. + * 6. OUT n-1, the output of counter channel n-1 (see note 1 below). + * 7. Ext Clock, the counter chip's dedicated Ext Clock input from + * the SK1 connector. This pin is shared by all three counter + * channels on the chip. + * + * INSN_CONFIG_GET_CLOCK_SRC. Returns the counter channel's current + * clock source in data[1]. For internal clock sources, data[2] is set + * to the period in ns. + * + * INSN_CONFIG_SET_GATE_SRC. Sets the counter channel's gate source as + * specified in data[2] (this is a hardware-specific value). Not + * supported on PC214E. For the other boards, valid gate sources are 0 + * to 7 as follows: + * + * 0. VCC (internal +5V d.c.), i.e. gate permanently enabled. + * 1. GND (internal 0V d.c.), i.e. gate permanently disabled. + * 2. GAT n, the counter channel's dedicated GAT input from the SK1 + * connector. (N.B. for other values, the counter channel's GATn + * pin on the SK1 connector is an output!) + * 3. /OUT n-2, the inverted output of counter channel n-2 (see note + * 2 below). + * 4. Reserved. + * 5. Reserved. + * 6. Reserved. + * 7. Reserved. + * + * INSN_CONFIG_GET_GATE_SRC. Returns the counter channel's current gate + * source in data[2]. + * + * Clock and gate interconnection notes: + * + * 1. Clock source OUT n-1 is the output of the preceding channel on the + * same counter subdevice if n > 0, or the output of channel 2 on the + * preceding counter subdevice (see note 3) if n = 0. + * + * 2. Gate source /OUT n-2 is the inverted output of channel 0 on the + * same counter subdevice if n = 2, or the inverted output of channel n+1 + * on the preceding counter subdevice (see note 3) if n < 2. + * + * 3. The counter subdevices are connected in a ring, so the highest + * counter subdevice precedes the lowest. + * + * The 'INTERRUPT' subdevice pretends to be a digital input subdevice. The + * digital inputs come from the interrupt status register. The number of + * channels matches the number of interrupt sources. The PC214E does not + * have an interrupt status register; see notes on 'INTERRUPT SOURCES' + * below. + * + * INTERRUPT SOURCES + * + * PC212E PC214E PC215E + * ------------- ------------- ------------- + * Sources 6 1 6 + * 0 PPI-X-C0 JUMPER-J5 PPI-X-C0 + * 1 PPI-X-C3 PPI-X-C3 + * 2 CTR-Y1-OUT1 PPI-Y-C0 + * 3 CTR-Y2-OUT1 PPI-Y-C3 + * 4 CTR-Z1-OUT1 CTR-Z1-OUT1 + * 5 CTR-Z2-OUT1 CTR-Z2-OUT1 + * + * PC218E PC272E + * ------------- ------------- + * Sources 6 6 + * 0 CTR-X1-OUT1 PPI-X-C0 + * 1 CTR-X2-OUT1 PPI-X-C3 + * 2 CTR-Y1-OUT1 PPI-Y-C0 + * 3 CTR-Y2-OUT1 PPI-Y-C3 + * 4 CTR-Z1-OUT1 PPI-Z-C0 + * 5 CTR-Z2-OUT1 PPI-Z-C3 + * + * When an interrupt source is enabled in the interrupt source enable + * register, a rising edge on the source signal latches the corresponding + * bit to 1 in the interrupt status register. + * + * When the interrupt status register value as a whole (actually, just the + * 6 least significant bits) goes from zero to non-zero, the board will + * generate an interrupt. No further interrupts will occur until the + * interrupt status register is cleared to zero. To clear a bit to zero in + * the interrupt status register, the corresponding interrupt source must + * be disabled in the interrupt source enable register (there is no + * separate interrupt clear register). + * + * The PC214E does not have an interrupt source enable register or an + * interrupt status register; its 'INTERRUPT' subdevice has a single + * channel and its interrupt source is selected by the position of jumper + * J5. + * + * COMMANDS + * + * The driver supports a read streaming acquisition command on the + * 'INTERRUPT' subdevice. The channel list selects the interrupt sources + * to be enabled. All channels will be sampled together (convert_src == + * TRIG_NOW). The scan begins a short time after the hardware interrupt + * occurs, subject to interrupt latencies (scan_begin_src == TRIG_EXT, + * scan_begin_arg == 0). The value read from the interrupt status register + * is packed into a short value, one bit per requested channel, in the + * order they appear in the channel list. */ -#define CLK_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source)) -#define GAT_SCE(which, chan, source) (((which) << 5) | ((chan) << 3) | (source)) -/* - * Periods of the internal clock sources in nanoseconds. - */ -static const unsigned clock_period[8] = { - 0, /* dedicated clock input/output pin */ - 100, /* 10 MHz */ - 1000, /* 1 MHz */ - 10000, /* 100 kHz */ - 100000, /* 10 kHz */ - 1000000, /* 1 kHz */ - 0, /* OUT N-1 */ - 0 /* group clock input pin */ -}; +#include <linux/module.h> +#include "../comedidev.h" + +#include "amplc_dio200.h" /* * Board descriptions. */ - -enum dio200_bustype { isa_bustype, pci_bustype }; - -enum dio200_model { - pc212e_model, - pc214e_model, - pc215e_model, pci215_model, - pc218e_model, - pc272e_model, pci272_model, - anypci_model -}; - -enum dio200_layout { - pc212_layout, - pc214_layout, - pc215_layout, - pc218_layout, - pc272_layout -}; - -struct dio200_board { - const char *name; - unsigned short devid; - enum dio200_bustype bustype; - enum dio200_model model; - enum dio200_layout layout; -}; - -static const struct dio200_board dio200_boards[] = { +static const struct dio200_board dio200_isa_boards[] = { { - .name = "pc212e", - .bustype = isa_bustype, - .model = pc212e_model, - .layout = pc212_layout, - }, + .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 = "pc214e", - .bustype = isa_bustype, - .model = pc214e_model, - .layout = pc214_layout, - }, + .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}, + }, + }, { - .name = "pc215e", - .bustype = isa_bustype, - .model = pc215e_model, - .layout = pc215_layout, - }, -#ifdef CONFIG_COMEDI_PCI + .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, + }, + }, { - .name = "pci215", - .devid = PCI_DEVICE_ID_AMPLICON_PCI215, - .bustype = pci_bustype, - .model = pci215_model, - .layout = pc215_layout, - }, -#endif - { - .name = "pc218e", - .bustype = isa_bustype, - .model = pc218e_model, - .layout = pc218_layout, - }, - { - .name = "pc272e", - .bustype = isa_bustype, - .model = pc272e_model, - .layout = pc272_layout, - }, -#ifdef CONFIG_COMEDI_PCI - { - .name = "pci272", - .devid = PCI_DEVICE_ID_AMPLICON_PCI272, - .bustype = pci_bustype, - .model = pci272_model, - .layout = pc272_layout, - }, -#endif -#ifdef CONFIG_COMEDI_PCI - { - .name = DIO200_DRIVER_NAME, - .devid = PCI_DEVICE_ID_INVALID, - .bustype = pci_bustype, - .model = anypci_model, /* wildcard */ - }, -#endif -}; - -/* - * Layout descriptions - some ISA and PCI board descriptions share the same - * layout. - */ - -enum dio200_sdtype { sd_none, sd_intr, sd_8255, sd_8254 }; - -#define DIO200_MAX_SUBDEVS 7 -#define DIO200_MAX_ISNS 6 - -struct dio200_layout_struct { - 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 */ - char has_int_sce; /* has interrupt enable/status register */ - char has_clk_gat_sce; /* has clock/gate selection registers */ -}; - -static const struct dio200_layout_struct dio200_layouts[] = { - [pc212_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 = 1, - .has_clk_gat_sce = 1, - }, - [pc214_layout] = { - .n_subdevs = 4, - .sdtype = {sd_8255, sd_8255, sd_8254, - sd_intr}, - .sdinfo = {0x00, 0x08, 0x10, 0x01}, - .has_int_sce = 0, - .has_clk_gat_sce = 0, - }, - [pc215_layout] = { - .n_subdevs = 5, - .sdtype = {sd_8255, sd_8255, sd_8254, - sd_8254, - sd_intr}, - .sdinfo = {0x00, 0x08, 0x10, 0x14, 0x3F}, - .has_int_sce = 1, - .has_clk_gat_sce = 1, - }, - [pc218_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 = 1, - .has_clk_gat_sce = 1, - }, - [pc272_layout] = { - .n_subdevs = 4, - .sdtype = {sd_8255, sd_8255, sd_8255, - sd_intr}, - .sdinfo = {0x00, 0x08, 0x10, 0x3F}, - .has_int_sce = 1, - .has_clk_gat_sce = 0, - }, -}; - -/* - * PCI driver table. - */ - -#ifdef CONFIG_COMEDI_PCI -static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = { + .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, + }, + }, { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, dio200_pci_table); -#endif /* CONFIG_COMEDI_PCI */ - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct dio200_board *)dev->board_ptr) -#define thislayout (&dio200_layouts[((struct dio200_board *) \ - dev->board_ptr)->layout]) - -/* 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 dio200_private { -#ifdef CONFIG_COMEDI_PCI - struct pci_dev *pci_dev; /* PCI device */ -#endif - int intr_sd; -}; - -#define devpriv ((struct dio200_private *)dev->private) - -struct dio200_subdev_8254 { - unsigned long iobase; /* Counter base address */ - unsigned long clk_sce_iobase; /* CLK_SCE base address */ - unsigned long gat_sce_iobase; /* GAT_SCE base address */ - int which; /* Bit 5 of CLK_SCE or GAT_SCE */ - int has_clk_gat_sce; - unsigned clock_src[3]; /* Current clock sources */ - unsigned gate_src[3]; /* Current gate sources */ - spinlock_t spinlock; + .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, + }, + }, }; -struct dio200_subdev_intr { - unsigned long iobase; - spinlock_t spinlock; - int active; - int has_int_sce; - unsigned int valid_isns; - unsigned int enabled_isns; - unsigned int stopcount; - int continuous; -}; - -/* - * 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 int dio200_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dio200_detach(struct comedi_device *dev); -static struct comedi_driver driver_amplc_dio200 = { - .driver_name = DIO200_DRIVER_NAME, - .module = THIS_MODULE, - .attach = dio200_attach, - .detach = dio200_detach, - .board_name = &dio200_boards[0].name, - .offset = sizeof(struct dio200_board), - .num_names = ARRAY_SIZE(dio200_boards), -}; - -#ifdef CONFIG_COMEDI_PCI -static int __devinit driver_amplc_dio200_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_amplc_dio200.driver_name); -} - -static void __devexit driver_amplc_dio200_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_amplc_dio200_pci_driver = { - .id_table = dio200_pci_table, - .probe = &driver_amplc_dio200_pci_probe, - .remove = __devexit_p(&driver_amplc_dio200_pci_remove) -}; - -static int __init driver_amplc_dio200_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_amplc_dio200); - if (retval < 0) - return retval; - - driver_amplc_dio200_pci_driver.name = - (char *)driver_amplc_dio200.driver_name; - return pci_register_driver(&driver_amplc_dio200_pci_driver); -} - -static void __exit driver_amplc_dio200_cleanup_module(void) -{ - pci_unregister_driver(&driver_amplc_dio200_pci_driver); - comedi_driver_unregister(&driver_amplc_dio200); -} - -module_init(driver_amplc_dio200_init_module); -module_exit(driver_amplc_dio200_cleanup_module); -#else -static int __init driver_amplc_dio200_init_module(void) -{ - return comedi_driver_register(&driver_amplc_dio200); -} - -static void __exit driver_amplc_dio200_cleanup_module(void) -{ - comedi_driver_unregister(&driver_amplc_dio200); -} - -module_init(driver_amplc_dio200_init_module); -module_exit(driver_amplc_dio200_cleanup_module); -#endif - -/* - * This function looks for a PCI device matching the requested board name, - * bus and slot. - */ -#ifdef CONFIG_COMEDI_PCI -static int -dio200_find_pci(struct comedi_device *dev, int bus, int slot, - struct pci_dev **pci_dev_p) -{ - struct pci_dev *pci_dev = NULL; - - *pci_dev_p = NULL; - - /* Look for matching PCI device. */ - for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL); - pci_dev != NULL; - pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, - PCI_ANY_ID, pci_dev)) { - /* If bus/slot specified, check them. */ - if (bus || slot) { - if (bus != pci_dev->bus->number - || slot != PCI_SLOT(pci_dev->devfn)) - continue; - } - if (thisboard->model == anypci_model) { - /* Match any supported model. */ - int i; - - for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) { - if (dio200_boards[i].bustype != pci_bustype) - continue; - if (pci_dev->device == dio200_boards[i].devid) { - /* Change board_ptr to matched board. */ - dev->board_ptr = &dio200_boards[i]; - break; - } - } - if (i == ARRAY_SIZE(dio200_boards)) - continue; - } else { - /* Match specific model name. */ - if (pci_dev->device != thisboard->devid) - continue; - } - - /* Found a match. */ - *pci_dev_p = pci_dev; - return 0; - } - /* No match found. */ - if (bus || slot) { - printk(KERN_ERR - "comedi%d: error! no %s found at pci %02x:%02x!\n", - dev->minor, thisboard->name, bus, slot); - } else { - printk(KERN_ERR "comedi%d: error! no %s found!\n", - dev->minor, thisboard->name); - } - return -EIO; -} -#endif - -/* - * This function checks and requests an I/O region, reporting an error - * if there is a conflict. - */ -static int -dio200_request_region(unsigned minor, unsigned long from, unsigned long extent) -{ - if (!from || !request_region(from, extent, DIO200_DRIVER_NAME)) { - printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n", - minor, from, extent); - return -EIO; - } - return 0; -} - -/* - * '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) -{ - struct dio200_subdev_intr *subpriv = s->private; - - if (subpriv->has_int_sce) { - /* Just read the interrupt status register. */ - data[1] = inb(subpriv->iobase) & subpriv->valid_isns; - } else { - /* No interrupt status register. */ - data[0] = 0; - } - - return 2; -} - -/* - * Called to stop acquisition for an 'INTERRUPT' subdevice. - */ -static void dio200_stop_intr(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct dio200_subdev_intr *subpriv = s->private; - - subpriv->active = 0; - subpriv->enabled_isns = 0; - if (subpriv->has_int_sce) - outb(0, subpriv->iobase); -} - -/* - * Called to start acquisition for an 'INTERRUPT' subdevice. - */ -static int dio200_start_intr(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned int n; - unsigned isn_bits; - struct dio200_subdev_intr *subpriv = s->private; - struct comedi_cmd *cmd = &s->async->cmd; - int retval = 0; - - if (!subpriv->continuous && subpriv->stopcount == 0) { - /* An empty acquisition! */ - s->async->events |= COMEDI_CB_EOA; - subpriv->active = 0; - 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 (subpriv->has_int_sce) - outb(isn_bits, subpriv->iobase); - } - - return retval; -} - -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) -{ - struct dio200_subdev_intr *subpriv; - unsigned long flags; - int event = 0; - - if (trignum != 0) - return -EINVAL; - - subpriv = s->private; - - spin_lock_irqsave(&subpriv->spinlock, flags); - s->async->inttrig = NULL; - if (subpriv->active) - event = dio200_start_intr(dev, s); - - spin_unlock_irqrestore(&subpriv->spinlock, flags); - - if (event) - comedi_event(dev, s); - - return 1; -} - -/* - * 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) -{ - struct dio200_subdev_intr *subpriv = s->private; - unsigned triggered; - unsigned intstat; - unsigned cur_enabled; - unsigned int oldevents; - unsigned long flags; - - triggered = 0; - - spin_lock_irqsave(&subpriv->spinlock, flags); - oldevents = s->async->events; - if (subpriv->has_int_sce) { - /* - * Collect interrupt sources that have triggered and disable - * them temporarily. Loop around until no extra interrupt - * sources have triggered, at which point, the valid part of - * the interrupt status register will read zero, clearing the - * cause of the interrupt. - * - * Mask off interrupt sources already seen to avoid infinite - * loop in case of misconfiguration. - */ - cur_enabled = subpriv->enabled_isns; - while ((intstat = (inb(subpriv->iobase) & subpriv->valid_isns - & ~triggered)) != 0) { - triggered |= intstat; - cur_enabled &= ~triggered; - outb(cur_enabled, subpriv->iobase); - } - } else { - /* - * No interrupt status register. Assume the single interrupt - * source has triggered. - */ - triggered = subpriv->enabled_isns; - } - - if (triggered) { - /* - * Some interrupt sources have triggered and have been - * temporarily disabled to clear the cause of the interrupt. - * - * Reenable them NOW to minimize the time they are disabled. - */ - cur_enabled = subpriv->enabled_isns; - if (subpriv->has_int_sce) - outb(cur_enabled, subpriv->iobase); - - if (subpriv->active) { - /* - * The command is still active. - * - * Ignore interrupt sources that the command isn't - * interested in (just in case there's a race - * condition). - */ - if (triggered & subpriv->enabled_isns) { - /* Collect scan data. */ - short val; - unsigned int n, ch, len; - - val = 0; - len = s->async->cmd.chanlist_len; - for (n = 0; n < len; n++) { - ch = CR_CHAN(s->async->cmd.chanlist[n]); - if (triggered & (1U << ch)) - val |= (1U << n); - } - /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, val)) { - s->async->events |= (COMEDI_CB_BLOCK | - COMEDI_CB_EOS); - } else { - /* Error! Stop acquisition. */ - dio200_stop_intr(dev, s); - s->async->events |= COMEDI_CB_ERROR - | COMEDI_CB_OVERFLOW; - comedi_error(dev, "buffer overflow"); - } - - /* Check for end of acquisition. */ - if (!subpriv->continuous) { - /* stop_src == TRIG_COUNT */ - if (subpriv->stopcount > 0) { - subpriv->stopcount--; - if (subpriv->stopcount == 0) { - s->async->events |= - COMEDI_CB_EOA; - dio200_stop_intr(dev, - s); - } - } - } - } - } - } - spin_unlock_irqrestore(&subpriv->spinlock, flags); - - if (oldevents != s->async->events) - comedi_event(dev, s); - - return (triggered != 0); -} - -/* - * 'cancel' function for an 'INTERRUPT' subdevice. - */ -static int dio200_subdev_intr_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct dio200_subdev_intr *subpriv = s->private; - unsigned long flags; - - spin_lock_irqsave(&subpriv->spinlock, flags); - if (subpriv->active) - dio200_stop_intr(dev, s); - - spin_unlock_irqrestore(&subpriv->spinlock, flags); - - 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) -{ - int err = 0; - unsigned int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= (TRIG_NOW | TRIG_INT); - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= (TRIG_COUNT | TRIG_NONE); - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) - return 1; - - /* step 2: make sure trigger sources are unique and mutually - compatible */ - - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; - - if (err) - return 2; - - /* step 3: make sure arguments are trivially compatible */ - - /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - - /* cmd->scan_begin_src == TRIG_EXT */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - - /* cmd->convert_src == TRIG_NOW */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - - /* cmd->scan_end_src == TRIG_COUNT */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - - switch (cmd->stop_src) { - case TRIG_COUNT: - /* any count allowed */ - break; - case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - break; - default: - break; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - /* if (err) return 4; */ - - 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 = 1; - - /* Set up end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - subpriv->continuous = 0; - subpriv->stopcount = cmd->stop_arg; - break; - default: - /* TRIG_NONE */ - subpriv->continuous = 1; - subpriv->stopcount = 0; - break; - } - - /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: - s->async->inttrig = dio200_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ - event = dio200_start_intr(dev, s); - break; - } - 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 long iobase, unsigned valid_isns, - int has_int_sce) -{ - struct dio200_subdev_intr *subpriv; - - subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); - if (!subpriv) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); - return -ENOMEM; - } - subpriv->iobase = iobase; - subpriv->has_int_sce = has_int_sce; - subpriv->valid_isns = valid_isns; - spin_lock_init(&subpriv->spinlock); - - if (has_int_sce) - outb(0, subpriv->iobase); /* Disable interrupt sources. */ - - s->private = subpriv; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - if (has_int_sce) { - s->n_chan = DIO200_MAX_ISNS; - s->len_chanlist = DIO200_MAX_ISNS; - } else { - /* No interrupt source register. Support single channel. */ - s->n_chan = 1; - s->len_chanlist = 1; - } - s->range_table = &range_digital; - s->maxdata = 1; - s->insn_bits = dio200_subdev_intr_insn_bits; - s->do_cmdtest = dio200_subdev_intr_cmdtest; - s->do_cmd = dio200_subdev_intr_cmd; - s->cancel = dio200_subdev_intr_cancel; - - return 0; -} - -/* - * This function cleans up an 'INTERRUPT' subdevice. - */ -static void -dio200_subdev_intr_cleanup(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct dio200_subdev_intr *subpriv = s->private; - kfree(subpriv); -} - -/* - * Interrupt service routine. - */ -static irqreturn_t dio200_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - int handled; - - if (!dev->attached) - return IRQ_NONE; - - if (devpriv->intr_sd >= 0) { - handled = dio200_handle_read_intr(dev, - dev->subdevices + - devpriv->intr_sd); - } else { - handled = 0; - } - - return IRQ_RETVAL(handled); -} - -/* - * 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) -{ - struct dio200_subdev_8254 *subpriv = s->private; - int chan = CR_CHAN(insn->chanspec); - unsigned long flags; - - spin_lock_irqsave(&subpriv->spinlock, flags); - data[0] = i8254_read(subpriv->iobase, 0, chan); - spin_unlock_irqrestore(&subpriv->spinlock, flags); - - return 1; -} - -/* - * 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) -{ - struct dio200_subdev_8254 *subpriv = s->private; - int chan = CR_CHAN(insn->chanspec); - unsigned long flags; - - spin_lock_irqsave(&subpriv->spinlock, flags); - i8254_write(subpriv->iobase, 0, chan, data[0]); - spin_unlock_irqrestore(&subpriv->spinlock, flags); - - return 1; -} - -/* - * Set gate source for an '8254' counter subdevice channel. - */ -static int -dio200_set_gate_src(struct dio200_subdev_8254 *subpriv, - unsigned int counter_number, unsigned int gate_src) -{ - unsigned char byte; - - if (!subpriv->has_clk_gat_sce) - return -1; - if (counter_number > 2) - return -1; - if (gate_src > 7) - return -1; - - subpriv->gate_src[counter_number] = gate_src; - byte = GAT_SCE(subpriv->which, counter_number, gate_src); - outb(byte, subpriv->gat_sce_iobase); - - return 0; -} - -/* - * Get gate source for an '8254' counter subdevice channel. - */ -static int -dio200_get_gate_src(struct dio200_subdev_8254 *subpriv, - unsigned int counter_number) -{ - if (!subpriv->has_clk_gat_sce) - return -1; - if (counter_number > 2) - return -1; - - return subpriv->gate_src[counter_number]; -} - -/* - * Set clock source for an '8254' counter subdevice channel. - */ -static int -dio200_set_clock_src(struct dio200_subdev_8254 *subpriv, - unsigned int counter_number, unsigned int clock_src) -{ - unsigned char byte; - - if (!subpriv->has_clk_gat_sce) - return -1; - if (counter_number > 2) - return -1; - if (clock_src > 7) - return -1; - - subpriv->clock_src[counter_number] = clock_src; - byte = CLK_SCE(subpriv->which, counter_number, clock_src); - outb(byte, subpriv->clk_sce_iobase); - - return 0; -} - -/* - * Get clock source for an '8254' counter subdevice channel. - */ -static int -dio200_get_clock_src(struct dio200_subdev_8254 *subpriv, - unsigned int counter_number, unsigned int *period_ns) -{ - unsigned clock_src; - - if (!subpriv->has_clk_gat_sce) - return -1; - if (counter_number > 2) - return -1; - - clock_src = subpriv->clock_src[counter_number]; - *period_ns = clock_period[clock_src]; - 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) -{ - struct dio200_subdev_8254 *subpriv = s->private; - int ret = 0; - int chan = CR_CHAN(insn->chanspec); - unsigned long flags; - - spin_lock_irqsave(&subpriv->spinlock, flags); - switch (data[0]) { - case INSN_CONFIG_SET_COUNTER_MODE: - ret = i8254_set_mode(subpriv->iobase, 0, chan, data[1]); - if (ret < 0) - ret = -EINVAL; - break; - case INSN_CONFIG_8254_READ_STATUS: - data[1] = i8254_status(subpriv->iobase, 0, chan); - break; - case INSN_CONFIG_SET_GATE_SRC: - ret = dio200_set_gate_src(subpriv, chan, data[2]); - if (ret < 0) - ret = -EINVAL; - break; - case INSN_CONFIG_GET_GATE_SRC: - ret = dio200_get_gate_src(subpriv, chan); - if (ret < 0) { - ret = -EINVAL; - break; - } - data[2] = ret; - break; - case INSN_CONFIG_SET_CLOCK_SRC: - ret = dio200_set_clock_src(subpriv, chan, data[1]); - if (ret < 0) - ret = -EINVAL; - break; - case INSN_CONFIG_GET_CLOCK_SRC: - ret = dio200_get_clock_src(subpriv, chan, &data[2]); - if (ret < 0) { - ret = -EINVAL; - break; - } - data[1] = ret; - break; - default: - ret = -EINVAL; - break; - } - spin_unlock_irqrestore(&subpriv->spinlock, flags); - return ret < 0 ? ret : insn->n; -} - -/* - * This function initializes an '8254' counter subdevice. - * - * Note: iobase is the base address of the board, not the subdevice; - * offset is the offset to the 8254 chip. - */ -static int -dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned long iobase, unsigned offset, - int has_clk_gat_sce) -{ - struct dio200_subdev_8254 *subpriv; - unsigned int chan; - - subpriv = kzalloc(sizeof(*subpriv), GFP_KERNEL); - if (!subpriv) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); - return -ENOMEM; - } - - s->private = subpriv; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 3; - s->maxdata = 0xFFFF; - s->insn_read = dio200_subdev_8254_read; - s->insn_write = dio200_subdev_8254_write; - s->insn_config = dio200_subdev_8254_config; - - spin_lock_init(&subpriv->spinlock); - subpriv->iobase = offset + iobase; - subpriv->has_clk_gat_sce = has_clk_gat_sce; - if (has_clk_gat_sce) { - /* Derive CLK_SCE and GAT_SCE register offsets from - * 8254 offset. */ - subpriv->clk_sce_iobase = - DIO200_XCLK_SCE + (offset >> 3) + iobase; - subpriv->gat_sce_iobase = - DIO200_XGAT_SCE + (offset >> 3) + iobase; - subpriv->which = (offset >> 2) & 1; - } - - /* Initialize channels. */ - for (chan = 0; chan < 3; chan++) { - i8254_set_mode(subpriv->iobase, 0, chan, - I8254_MODE0 | I8254_BINARY); - if (subpriv->has_clk_gat_sce) { - /* Gate source 0 is VCC (logic 1). */ - dio200_set_gate_src(subpriv, chan, 0); - /* Clock source 0 is the dedicated clock input. */ - dio200_set_clock_src(subpriv, chan, 0); - } - } - - return 0; -} - -/* - * This function cleans up an '8254' counter subdevice. - */ -static void -dio200_subdev_8254_cleanup(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - struct dio200_subdev_intr *subpriv = s->private; - kfree(subpriv); -} - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - struct comedi_subdevice *s; - unsigned long iobase = 0; - unsigned int irq = 0; -#ifdef CONFIG_COMEDI_PCI - struct pci_dev *pci_dev = NULL; - int bus = 0, slot = 0; -#endif - const struct dio200_layout_struct *layout; - int share_irq = 0; - int sdx; - unsigned n; + const struct dio200_board *thisboard = comedi_board(dev); + struct dio200_private *devpriv; + unsigned int irq; int ret; - printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, - DIO200_DRIVER_NAME); - - ret = alloc_private(dev, sizeof(struct dio200_private)); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); - return ret; - } - - /* Process options. */ - switch (thisboard->bustype) { - case isa_bustype: - iobase = it->options[0]; - irq = it->options[1]; - share_irq = 0; - break; -#ifdef CONFIG_COMEDI_PCI - case pci_bustype: - bus = it->options[0]; - slot = it->options[1]; - share_irq = 1; - - ret = dio200_find_pci(dev, bus, slot, &pci_dev); - if (ret < 0) - return ret; - devpriv->pci_dev = pci_dev; - break; -#endif - default: - printk(KERN_ERR - "comedi%d: %s: BUG! cannot determine board type!\n", - dev->minor, DIO200_DRIVER_NAME); - return -EINVAL; - break; - } - - devpriv->intr_sd = -1; - - /* Enable device and reserve I/O spaces. */ -#ifdef CONFIG_COMEDI_PCI - if (pci_dev) { - ret = comedi_pci_enable(pci_dev, DIO200_DRIVER_NAME); - if (ret < 0) { - printk(KERN_ERR - "comedi%d: error! cannot enable PCI device and request regions!\n", - dev->minor); - return ret; - } - iobase = pci_resource_start(pci_dev, 2); - irq = pci_dev->irq; - } else -#endif - { - ret = dio200_request_region(dev->minor, iobase, DIO200_IO_SIZE); - if (ret < 0) - return ret; - } - dev->iobase = iobase; + irq = it->options[1]; - layout = thislayout; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = alloc_subdevices(dev, layout->n_subdevs); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); + ret = comedi_request_region(dev, it->options[0], thisboard->mainsize); + if (ret) return ret; - } - - for (n = 0; n < dev->n_subdevices; n++) { - s = &dev->subdevices[n]; - switch (layout->sdtype[n]) { - case sd_8254: - /* counter subdevice (8254) */ - ret = dio200_subdev_8254_init(dev, s, iobase, - layout->sdinfo[n], - layout->has_clk_gat_sce); - if (ret < 0) - return ret; - - break; - case sd_8255: - /* digital i/o subdevice (8255) */ - ret = subdev_8255_init(dev, s, NULL, - iobase + layout->sdinfo[n]); - if (ret < 0) - return ret; - - break; - case sd_intr: - /* 'INTERRUPT' subdevice */ - if (irq) { - ret = dio200_subdev_intr_init(dev, s, - iobase + - DIO200_INT_SCE, - layout->sdinfo[n], - layout-> - has_int_sce); - if (ret < 0) - return ret; - - devpriv->intr_sd = n; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - 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]; - - dev->board_name = thisboard->name; - - if (irq) { - unsigned long flags = share_irq ? IRQF_SHARED : 0; - - if (request_irq(irq, dio200_interrupt, flags, - DIO200_DRIVER_NAME, dev) >= 0) { - dev->irq = irq; - } else { - printk(KERN_WARNING - "comedi%d: warning! irq %u unavailable!\n", - dev->minor, irq); - } - } - - printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name); - if (thisboard->bustype == isa_bustype) { - printk("(base %#lx) ", iobase); - } else { -#ifdef CONFIG_COMEDI_PCI - printk("(pci %s) ", pci_name(pci_dev)); -#endif - } - if (irq) - printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE")); - else - printk("(no irq) "); - - printk("attached\n"); - - return 1; + devpriv->io.u.iobase = dev->iobase; + devpriv->io.regtype = io_regtype; + return amplc_dio200_common_attach(dev, irq, 0); } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int dio200_detach(struct comedi_device *dev) +static void dio200_detach(struct comedi_device *dev) { - const struct dio200_layout_struct *layout; - unsigned n; - - printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, - DIO200_DRIVER_NAME); - - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->subdevices) { - layout = thislayout; - for (n = 0; n < dev->n_subdevices; n++) { - struct comedi_subdevice *s = &dev->subdevices[n]; - switch (layout->sdtype[n]) { - case sd_8254: - dio200_subdev_8254_cleanup(dev, s); - break; - case sd_8255: - subdev_8255_cleanup(dev, s); - break; - case sd_intr: - dio200_subdev_intr_cleanup(dev, s); - break; - default: - break; - } - } - } - if (devpriv) { -#ifdef CONFIG_COMEDI_PCI - if (devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } else -#endif - { - if (dev->iobase) - release_region(dev->iobase, DIO200_IO_SIZE); - } - } - if (dev->board_name) - printk(KERN_INFO "comedi%d: %s removed\n", - dev->minor, dev->board_name); - - return 0; + amplc_dio200_common_detach(dev); + comedi_legacy_detach(dev); } +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), +}; +module_comedi_driver(amplc_dio200_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Amplicon 200 Series ISA DIO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_dio200.h b/drivers/staging/comedi/drivers/amplc_dio200.h new file mode 100644 index 00000000000..43160b9944b --- /dev/null +++ b/drivers/staging/comedi/drivers/amplc_dio200.h @@ -0,0 +1,90 @@ +/* + comedi/drivers/amplc_dio.h + + Header for amplc_dio200.c, amplc_dio200_common.c and + amplc_dio200_pci.c. + + Copyright (C) 2005-2013 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. +*/ + +#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 + +/* + * Register region. + */ +enum dio200_regtype { no_regtype = 0, io_regtype, mmio_regtype }; +struct dio200_region { + union { + unsigned long iobase; /* I/O base address */ + unsigned char __iomem *membase; /* mapped MMIO base address */ + } u; + enum dio200_regtype regtype; +}; + +/* + * Subdevice types. + */ +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 { + 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 { + struct dio200_region io; /* Register region */ + int intr_sd; +}; + +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); + +#endif diff --git a/drivers/staging/comedi/drivers/amplc_dio200_common.c b/drivers/staging/comedi/drivers/amplc_dio200_common.c new file mode 100644 index 00000000000..3edaa4028da --- /dev/null +++ b/drivers/staging/comedi/drivers/amplc_dio200_common.c @@ -0,0 +1,1223 @@ +/* + comedi/drivers/amplc_dio200_common.c + + Common support code for "amplc_dio200" and "amplc_dio200_pci". + + Copyright (C) 2005-2013 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. +*/ + +#include <linux/module.h> +#include <linux/interrupt.h> + +#include "../comedidev.h" + +#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 + +/* 200 series registers */ +#define DIO200_IO_SIZE 0x20 +#define DIO200_PCIE_IO_SIZE 0x4000 +#define DIO200_XCLK_SCE 0x18 /* Group X clock selection register */ +#define DIO200_YCLK_SCE 0x19 /* Group Y clock selection register */ +#define DIO200_ZCLK_SCE 0x1a /* Group Z clock selection register */ +#define DIO200_XGAT_SCE 0x1b /* Group X gate selection register */ +#define DIO200_YGAT_SCE 0x1c /* Group Y gate selection register */ +#define DIO200_ZGAT_SCE 0x1d /* Group Z gate selection register */ +#define DIO200_INT_SCE 0x1e /* Interrupt enable/status register */ +/* Extra registers for new PCIe boards */ +#define DIO200_ENHANCE 0x20 /* 1 to enable enhanced features */ +#define DIO200_VERSION 0x24 /* Hardware version register */ +#define DIO200_TS_CONFIG 0x600 /* Timestamp timer config register */ +#define DIO200_TS_COUNT 0x602 /* Timestamp timer count register */ + +/* + * Functions for constructing value for DIO_200_?CLK_SCE and + * DIO_200_?GAT_SCE registers: + * + * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2. + * 'chan' is the channel: 0, 1 or 2. + * 'source' is the signal source: 0 to 7, or 0 to 31 for "enhanced" boards. + */ +static unsigned char clk_gat_sce(unsigned int which, unsigned int chan, + unsigned int source) +{ + return (which << 5) | (chan << 3) | + ((source & 030) << 3) | (source & 007); +} + +static unsigned char clk_sce(unsigned int which, unsigned int chan, + unsigned int source) +{ + return clk_gat_sce(which, chan, source); +} + +static unsigned char gat_sce(unsigned int which, unsigned int chan, + unsigned int source) +{ + return clk_gat_sce(which, chan, source); +} + +/* + * Periods of the internal clock sources in nanoseconds. + */ +static const unsigned int clock_period[32] = { + [1] = 100, /* 10 MHz */ + [2] = 1000, /* 1 MHz */ + [3] = 10000, /* 100 kHz */ + [4] = 100000, /* 10 kHz */ + [5] = 1000000, /* 1 kHz */ + [11] = 50, /* 20 MHz (enhanced boards) */ + /* clock sources 12 and later reserved for enhanced boards */ +}; + +/* + * Timestamp timer configuration register (for new PCIe boards). + */ +#define TS_CONFIG_RESET 0x100 /* Reset counter to zero. */ +#define TS_CONFIG_CLK_SRC_MASK 0x0FF /* Clock source. */ +#define TS_CONFIG_MAX_CLK_SRC 2 /* Maximum clock source value. */ + +/* + * Periods of the timestamp timer clock sources in nanoseconds. + */ +static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = { + 1, /* 1 nanosecond (but with 20 ns granularity). */ + 1000, /* 1 microsecond. */ + 1000000, /* 1 millisecond. */ +}; + +struct dio200_subdev_8254 { + unsigned int ofs; /* Counter base offset */ + unsigned int clk_sce_ofs; /* CLK_SCE base address */ + unsigned int gat_sce_ofs; /* GAT_SCE base address */ + int which; /* Bit 5 of CLK_SCE or GAT_SCE */ + unsigned int clock_src[3]; /* Current clock sources */ + unsigned int gate_src[3]; /* Current gate sources */ + spinlock_t spinlock; +}; + +struct dio200_subdev_8255 { + unsigned int ofs; /* DIO base offset */ +}; + +struct dio200_subdev_intr { + spinlock_t spinlock; + unsigned int ofs; + unsigned int valid_isns; + unsigned int enabled_isns; + unsigned int stopcount; + 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); + struct dio200_private *devpriv = dev->private; + + offset <<= thisboard->mainshift; + if (devpriv->io.regtype == io_regtype) + return inb(devpriv->io.u.iobase + offset); + else + return readb(devpriv->io.u.membase + offset); +} + +/* + * Write 8-bit register. + */ +static void dio200_write8(struct comedi_device *dev, unsigned int offset, + unsigned char val) +{ + const struct dio200_board *thisboard = comedi_board(dev); + struct dio200_private *devpriv = dev->private; + + offset <<= thisboard->mainshift; + if (devpriv->io.regtype == io_regtype) + outb(val, devpriv->io.u.iobase + offset); + else + writeb(val, devpriv->io.u.membase + 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); + struct dio200_private *devpriv = dev->private; + + offset <<= thisboard->mainshift; + if (devpriv->io.regtype == io_regtype) + return inl(devpriv->io.u.iobase + offset); + else + return readl(devpriv->io.u.membase + offset); +} + +/* + * Write 32-bit register. + */ +static void dio200_write32(struct comedi_device *dev, unsigned int offset, + unsigned int val) +{ + const struct dio200_board *thisboard = comedi_board(dev); + struct dio200_private *devpriv = dev->private; + + offset <<= thisboard->mainshift; + if (devpriv->io.regtype == io_regtype) + outl(val, devpriv->io.u.iobase + offset); + else + writel(val, devpriv->io.u.membase + 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) +{ + const struct dio200_layout *layout = dio200_dev_layout(dev); + struct dio200_subdev_intr *subpriv = s->private; + + if (layout->has_int_sce) { + /* Just read the interrupt status register. */ + data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns; + } else { + /* No interrupt status register. */ + data[0] = 0; + } + + 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); + struct dio200_subdev_intr *subpriv = s->private; + + subpriv->active = false; + subpriv->enabled_isns = 0; + if (layout->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) +{ + unsigned int n; + unsigned isn_bits; + const struct dio200_layout *layout = dio200_dev_layout(dev); + struct dio200_subdev_intr *subpriv = s->private; + struct comedi_cmd *cmd = &s->async->cmd; + int retval = 0; + + 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); + } + + return retval; +} + +static int dio200_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) +{ + 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; + + spin_lock_irqsave(&subpriv->spinlock, flags); + s->async->inttrig = NULL; + if (subpriv->active) + event = dio200_start_intr(dev, s); + + spin_unlock_irqrestore(&subpriv->spinlock, flags); + + if (event) + comedi_event(dev, s); + + return 1; +} + +static void dio200_read_scan_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int triggered) +{ + struct dio200_subdev_intr *subpriv = s->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned short val; + unsigned int n, ch; + + val = 0; + for (n = 0; n < cmd->chanlist_len; n++) { + ch = CR_CHAN(cmd->chanlist[n]); + if (triggered & (1U << ch)) + val |= (1U << n); + } + /* Write the scan to the buffer. */ + if (comedi_buf_put(s, val)) { + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + } else { + /* Error! Stop acquisition. */ + dio200_stop_intr(dev, s); + s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; + comedi_error(dev, "buffer overflow"); + } + + /* Check for end of acquisition. */ + if (cmd->stop_src == TRIG_COUNT) { + if (subpriv->stopcount > 0) { + subpriv->stopcount--; + if (subpriv->stopcount == 0) { + s->async->events |= COMEDI_CB_EOA; + dio200_stop_intr(dev, s); + } + } + } +} + +/* + * 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); + struct dio200_subdev_intr *subpriv = s->private; + unsigned triggered; + unsigned intstat; + unsigned cur_enabled; + unsigned int oldevents; + unsigned long flags; + + triggered = 0; + + spin_lock_irqsave(&subpriv->spinlock, flags); + oldevents = s->async->events; + if (layout->has_int_sce) { + /* + * Collect interrupt sources that have triggered and disable + * them temporarily. Loop around until no extra interrupt + * sources have triggered, at which point, the valid part of + * the interrupt status register will read zero, clearing the + * cause of the interrupt. + * + * Mask off interrupt sources already seen to avoid infinite + * loop in case of misconfiguration. + */ + cur_enabled = subpriv->enabled_isns; + while ((intstat = (dio200_read8(dev, subpriv->ofs) & + subpriv->valid_isns & ~triggered)) != 0) { + triggered |= intstat; + cur_enabled &= ~triggered; + dio200_write8(dev, subpriv->ofs, cur_enabled); + } + } else { + /* + * No interrupt status register. Assume the single interrupt + * source has triggered. + */ + triggered = subpriv->enabled_isns; + } + + if (triggered) { + /* + * Some interrupt sources have triggered and have been + * temporarily disabled to clear the cause of the interrupt. + * + * Reenable them NOW to minimize the time they are disabled. + */ + cur_enabled = subpriv->enabled_isns; + if (layout->has_int_sce) + dio200_write8(dev, subpriv->ofs, cur_enabled); + + if (subpriv->active) { + /* + * The command is still active. + * + * Ignore interrupt sources that the command isn't + * interested in (just in case there's a race + * condition). + */ + if (triggered & subpriv->enabled_isns) + /* Collect scan data. */ + dio200_read_scan_intr(dev, s, triggered); + } + } + spin_unlock_irqrestore(&subpriv->spinlock, flags); + + if (oldevents != s->async->events) + comedi_event(dev, s); + + return (triggered != 0); +} + +/* + * 'cancel' function for an 'INTERRUPT' subdevice. + */ +static int dio200_subdev_intr_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct dio200_subdev_intr *subpriv = s->private; + unsigned long flags; + + spin_lock_irqsave(&subpriv->spinlock, flags); + if (subpriv->active) + dio200_stop_intr(dev, s); + + spin_unlock_irqrestore(&subpriv->spinlock, flags); + + 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) +{ + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_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); + 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); + + switch (cmd->stop_src) { + case TRIG_COUNT: + /* any count allowed */ + break; + case TRIG_NONE: + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + break; + default: + break; + } + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + /* if (err) return 4; */ + + 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; + + if (cmd->start_src == TRIG_INT) + s->async->inttrig = dio200_inttrig_start_intr; + else /* TRIG_NOW */ + event = 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) +{ + const struct dio200_layout *layout = dio200_dev_layout(dev); + struct dio200_subdev_intr *subpriv; + + subpriv = comedi_alloc_spriv(s, sizeof(*subpriv)); + if (!subpriv) + return -ENOMEM; + + subpriv->ofs = offset; + subpriv->valid_isns = valid_isns; + spin_lock_init(&subpriv->spinlock); + + if (layout->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) { + s->n_chan = DIO200_MAX_ISNS; + s->len_chanlist = DIO200_MAX_ISNS; + } else { + /* No interrupt source register. Support single channel. */ + s->n_chan = 1; + s->len_chanlist = 1; + } + s->range_table = &range_digital; + s->maxdata = 1; + s->insn_bits = dio200_subdev_intr_insn_bits; + s->do_cmdtest = dio200_subdev_intr_cmdtest; + s->do_cmd = dio200_subdev_intr_cmd; + s->cancel = dio200_subdev_intr_cancel; + + 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; + 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; + } + + 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) +{ + struct dio200_subdev_8254 *subpriv = s->private; + unsigned int val; + + /* latch counter */ + val = chan << 6; + dio200_write8(dev, subpriv->ofs + i8254_control_reg, val); + /* read lsb, msb */ + val = dio200_read8(dev, subpriv->ofs + chan); + val += dio200_read8(dev, subpriv->ofs + chan) << 8; + 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) +{ + struct dio200_subdev_8254 *subpriv = s->private; + + /* write lsb, msb */ + dio200_write8(dev, subpriv->ofs + chan, count & 0xff); + 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) +{ + struct dio200_subdev_8254 *subpriv = s->private; + unsigned int byte; + + byte = chan << 6; + byte |= 0x30; /* access order: lsb, msb */ + byte |= (mode & 0xf); /* counter mode and BCD|binary */ + 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) +{ + struct dio200_subdev_8254 *subpriv = s->private; + + /* latch status */ + dio200_write8(dev, subpriv->ofs + i8254_control_reg, + 0xe0 | (2 << chan)); + /* read status */ + 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) +{ + struct dio200_subdev_8254 *subpriv = s->private; + int chan = CR_CHAN(insn->chanspec); + unsigned int n; + unsigned long flags; + + for (n = 0; n < insn->n; n++) { + spin_lock_irqsave(&subpriv->spinlock, flags); + data[n] = dio200_subdev_8254_read_chan(dev, s, chan); + spin_unlock_irqrestore(&subpriv->spinlock, flags); + } + 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) +{ + struct dio200_subdev_8254 *subpriv = s->private; + int chan = CR_CHAN(insn->chanspec); + unsigned int n; + unsigned long flags; + + for (n = 0; n < insn->n; n++) { + spin_lock_irqsave(&subpriv->spinlock, flags); + dio200_subdev_8254_write_chan(dev, s, chan, data[n]); + spin_unlock_irqrestore(&subpriv->spinlock, flags); + } + 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) +{ + const struct dio200_layout *layout = dio200_dev_layout(dev); + struct dio200_subdev_8254 *subpriv = s->private; + unsigned char byte; + + if (!layout->has_clk_gat_sce) + return -1; + if (counter_number > 2) + return -1; + if (gate_src > (layout->has_enhancements ? 31 : 7)) + return -1; + + subpriv->gate_src[counter_number] = gate_src; + byte = gat_sce(subpriv->which, counter_number, gate_src); + dio200_write8(dev, subpriv->gat_sce_ofs, byte); + + 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) +{ + const struct dio200_layout *layout = dio200_dev_layout(dev); + struct dio200_subdev_8254 *subpriv = s->private; + + if (!layout->has_clk_gat_sce) + return -1; + if (counter_number > 2) + return -1; + + 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) +{ + const struct dio200_layout *layout = dio200_dev_layout(dev); + struct dio200_subdev_8254 *subpriv = s->private; + unsigned char byte; + + if (!layout->has_clk_gat_sce) + return -1; + if (counter_number > 2) + return -1; + if (clock_src > (layout->has_enhancements ? 31 : 7)) + return -1; + + subpriv->clock_src[counter_number] = clock_src; + byte = clk_sce(subpriv->which, counter_number, clock_src); + dio200_write8(dev, subpriv->clk_sce_ofs, byte); + + 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) +{ + const struct dio200_layout *layout = dio200_dev_layout(dev); + struct dio200_subdev_8254 *subpriv = s->private; + unsigned clock_src; + + if (!layout->has_clk_gat_sce) + return -1; + if (counter_number > 2) + return -1; + + clock_src = subpriv->clock_src[counter_number]; + *period_ns = clock_period[clock_src]; + 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) +{ + struct dio200_subdev_8254 *subpriv = s->private; + int ret = 0; + int chan = CR_CHAN(insn->chanspec); + unsigned long flags; + + spin_lock_irqsave(&subpriv->spinlock, flags); + switch (data[0]) { + case INSN_CONFIG_SET_COUNTER_MODE: + if (data[1] > (I8254_MODE5 | I8254_BCD)) + ret = -EINVAL; + else + dio200_subdev_8254_set_mode(dev, s, chan, data[1]); + break; + case INSN_CONFIG_8254_READ_STATUS: + data[1] = dio200_subdev_8254_status(dev, s, chan); + break; + case INSN_CONFIG_SET_GATE_SRC: + ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]); + if (ret < 0) + ret = -EINVAL; + break; + case INSN_CONFIG_GET_GATE_SRC: + ret = dio200_subdev_8254_get_gate_src(dev, s, chan); + if (ret < 0) { + ret = -EINVAL; + break; + } + data[2] = ret; + break; + case INSN_CONFIG_SET_CLOCK_SRC: + ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]); + if (ret < 0) + ret = -EINVAL; + break; + case INSN_CONFIG_GET_CLOCK_SRC: + ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]); + if (ret < 0) { + ret = -EINVAL; + break; + } + data[1] = ret; + break; + default: + ret = -EINVAL; + break; + } + spin_unlock_irqrestore(&subpriv->spinlock, flags); + 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) +{ + const struct dio200_layout *layout = dio200_dev_layout(dev); + struct dio200_subdev_8254 *subpriv; + unsigned int chan; + + subpriv = comedi_alloc_spriv(s, sizeof(*subpriv)); + if (!subpriv) + return -ENOMEM; + + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 3; + s->maxdata = 0xFFFF; + s->insn_read = dio200_subdev_8254_read; + s->insn_write = dio200_subdev_8254_write; + s->insn_config = dio200_subdev_8254_config; + + spin_lock_init(&subpriv->spinlock); + subpriv->ofs = offset; + if (layout->has_clk_gat_sce) { + /* Derive CLK_SCE and GAT_SCE register offsets from + * 8254 offset. */ + subpriv->clk_sce_ofs = DIO200_XCLK_SCE + (offset >> 3); + subpriv->gat_sce_ofs = DIO200_XGAT_SCE + (offset >> 3); + subpriv->which = (offset >> 2) & 1; + } + + /* Initialize channels. */ + for (chan = 0; chan < 3; chan++) { + dio200_subdev_8254_set_mode(dev, s, chan, + I8254_MODE0 | I8254_BINARY); + if (layout->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. */ + dio200_subdev_8254_set_clock_src(dev, s, chan, 0); + } + } + + 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; + /* 1 in io_bits indicates output, 1 in config indicates input */ + if (!(s->io_bits & 0x0000ff)) + config |= CR_A_IO; + if (!(s->io_bits & 0x00ff00)) + config |= CR_B_IO; + if (!(s->io_bits & 0x0f0000)) + config |= CR_C_LO_IO; + if (!(s->io_bits & 0xf00000)) + config |= CR_C_HI_IO; + dio200_write8(dev, subpriv->ofs + 3, config); +} + +static int dio200_subdev_8255_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dio200_subdev_8255 *subpriv = s->private; + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0xff) + dio200_write8(dev, subpriv->ofs, s->state & 0xff); + if (mask & 0xff00) + dio200_write8(dev, subpriv->ofs + 1, + (s->state >> 8) & 0xff); + if (mask & 0xff0000) + dio200_write8(dev, subpriv->ofs + 2, + (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; + + 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, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 8) + mask = 0x0000ff; + else if (chan < 16) + mask = 0x00ff00; + else if (chan < 20) + mask = 0x0f0000; + else + mask = 0xf00000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + dio200_subdev_8255_set_dir(dev, s); + + 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) +{ + struct dio200_subdev_8255 *subpriv; + + subpriv = comedi_alloc_spriv(s, sizeof(*subpriv)); + if (!subpriv) + return -ENOMEM; + + subpriv->ofs = offset; + + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->range_table = &range_digital; + s->maxdata = 1; + s->insn_bits = dio200_subdev_8255_bits; + s->insn_config = dio200_subdev_8255_config; + dio200_subdev_8255_set_dir(dev, s); + 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, + unsigned int *data) +{ + unsigned int n; + + for (n = 0; n < insn->n; n++) + data[n] = dio200_read32(dev, DIO200_TS_COUNT); + return n; +} + +/* + * Reset timer subdevice. + */ +static void dio200_subdev_timer_reset(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int clock; + + clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK; + dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET); + 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, + unsigned int *period) +{ + unsigned int clk; + + clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK; + *src = clk; + *period = (clk < ARRAY_SIZE(ts_clock_period)) ? + 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) +{ + if (src > TS_CONFIG_MAX_CLK_SRC) + return -EINVAL; + dio200_write32(dev, DIO200_TS_CONFIG, src); + 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, + unsigned int *data) +{ + int ret = 0; + + switch (data[0]) { + case INSN_CONFIG_RESET: + dio200_subdev_timer_reset(dev, s); + break; + case INSN_CONFIG_SET_CLOCK_SRC: + ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]); + if (ret < 0) + ret = -EINVAL; + break; + case INSN_CONFIG_GET_CLOCK_SRC: + dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]); + break; + default: + ret = -EINVAL; + break; + } + 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); +} +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); + struct comedi_subdevice *s; + int sdx; + unsigned int n; + int ret; + + devpriv->intr_sd = -1; + + ret = comedi_alloc_subdevices(dev, layout->n_subdevs); + if (ret) + return ret; + + for (n = 0; n < dev->n_subdevices; n++) { + s = &dev->subdevices[n]; + switch (layout->sdtype[n]) { + case sd_8254: + /* counter subdevice (8254) */ + ret = dio200_subdev_8254_init(dev, s, + layout->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]); + if (ret < 0) + return ret; + break; + case sd_intr: + /* 'INTERRUPT' subdevice */ + if (irq) { + ret = dio200_subdev_intr_init(dev, s, + DIO200_INT_SCE, + layout->sdinfo[n] + ); + if (ret < 0) + return ret; + devpriv->intr_sd = n; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + break; + case sd_timer: + ret = dio200_subdev_timer_init(dev, s); + if (ret < 0) + return ret; + 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 (request_irq(irq, dio200_interrupt, req_irq_flags, + dev->board_name, dev) >= 0) { + dev->irq = irq; + } else { + dev_warn(dev->class_dev, + "warning! irq %u unavailable!\n", irq); + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(amplc_dio200_common_attach); + +void amplc_dio200_common_detach(struct comedi_device *dev) +{ + const struct dio200_board *thisboard = comedi_board(dev); + struct dio200_private *devpriv = dev->private; + + if (!thisboard || !devpriv) + return; + if (dev->irq) + free_irq(dev->irq, dev); +} +EXPORT_SYMBOL_GPL(amplc_dio200_common_detach); + +static int __init amplc_dio200_common_init(void) +{ + return 0; +} +module_init(amplc_dio200_common_init); + +static void __exit amplc_dio200_common_exit(void) +{ +} +module_exit(amplc_dio200_common_exit); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi helper for amplc_dio200 and amplc_dio200_pci"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_dio200_pci.c b/drivers/staging/comedi/drivers/amplc_dio200_pci.c new file mode 100644 index 00000000000..e0367380b37 --- /dev/null +++ b/drivers/staging/comedi/drivers/amplc_dio200_pci.c @@ -0,0 +1,480 @@ +/* comedi/drivers/amplc_dio200_pci.c + + Driver for Amplicon PCI215, PCI272, PCIe215, PCIe236, PCIe296. + + Copyright (C) 2005-2013 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. +*/ +/* + * Driver: amplc_dio200_pci + * Description: Amplicon 200 Series PCI Digital I/O + * Author: Ian Abbott <abbotti@mev.co.uk> + * Devices: [Amplicon] PCI215 (amplc_dio200_pci), PCIe215, PCIe236, + * PCI272, PCIe296 + * Updated: Mon, 18 Mar 2013 15:03:50 +0000 + * Status: works + * + * Configuration options: + * none + * + * Manual configuration of PCI(e) cards is not supported; they are configured + * automatically. + * + * SUBDEVICES + * + * PCI215 PCIe215 PCIe236 + * ------------- ------------- ------------- + * Subdevices 5 8 8 + * 0 PPI-X PPI-X PPI-X + * 1 PPI-Y UNUSED UNUSED + * 2 CTR-Z1 PPI-Y UNUSED + * 3 CTR-Z2 UNUSED UNUSED + * 4 INTERRUPT CTR-Z1 CTR-Z1 + * 5 CTR-Z2 CTR-Z2 + * 6 TIMER TIMER + * 7 INTERRUPT INTERRUPT + * + * + * PCI272 PCIe296 + * ------------- ------------- + * Subdevices 4 8 + * 0 PPI-X PPI-X1 + * 1 PPI-Y PPI-X2 + * 2 PPI-Z PPI-Y1 + * 3 INTERRUPT PPI-Y2 + * 4 CTR-Z1 + * 5 CTR-Z2 + * 6 TIMER + * 7 INTERRUPT + * + * Each PPI is a 8255 chip providing 24 DIO channels. The DIO channels + * are configurable as inputs or outputs in four groups: + * + * Port A - channels 0 to 7 + * Port B - channels 8 to 15 + * Port CL - channels 16 to 19 + * Port CH - channels 20 to 23 + * + * Only mode 0 of the 8255 chips is supported. + * + * Each CTR is a 8254 chip providing 3 16-bit counter channels. Each + * channel is configured individually with INSN_CONFIG instructions. The + * specific type of configuration instruction is specified in data[0]. + * Some configuration instructions expect an additional parameter in + * data[1]; others return a value in data[1]. The following configuration + * instructions are supported: + * + * INSN_CONFIG_SET_COUNTER_MODE. Sets the counter channel's mode and + * BCD/binary setting specified in data[1]. + * + * INSN_CONFIG_8254_READ_STATUS. Reads the status register value for the + * counter channel into data[1]. + * + * INSN_CONFIG_SET_CLOCK_SRC. Sets the counter channel's clock source as + * specified in data[1] (this is a hardware-specific value). Not + * supported on PC214E. For the other boards, valid clock sources are + * 0 to 7 as follows: + * + * 0. CLK n, the counter channel's dedicated CLK input from the SK1 + * connector. (N.B. for other values, the counter channel's CLKn + * pin on the SK1 connector is an output!) + * 1. Internal 10 MHz clock. + * 2. Internal 1 MHz clock. + * 3. Internal 100 kHz clock. + * 4. Internal 10 kHz clock. + * 5. Internal 1 kHz clock. + * 6. OUT n-1, the output of counter channel n-1 (see note 1 below). + * 7. Ext Clock, the counter chip's dedicated Ext Clock input from + * the SK1 connector. This pin is shared by all three counter + * channels on the chip. + * + * For the PCIe boards, clock sources in the range 0 to 31 are allowed + * and the following additional clock sources are defined: + * + * 8. HIGH logic level. + * 9. LOW logic level. + * 10. "Pattern present" signal. + * 11. Internal 20 MHz clock. + * + * INSN_CONFIG_GET_CLOCK_SRC. Returns the counter channel's current + * clock source in data[1]. For internal clock sources, data[2] is set + * to the period in ns. + * + * INSN_CONFIG_SET_GATE_SRC. Sets the counter channel's gate source as + * specified in data[2] (this is a hardware-specific value). Not + * supported on PC214E. For the other boards, valid gate sources are 0 + * to 7 as follows: + * + * 0. VCC (internal +5V d.c.), i.e. gate permanently enabled. + * 1. GND (internal 0V d.c.), i.e. gate permanently disabled. + * 2. GAT n, the counter channel's dedicated GAT input from the SK1 + * connector. (N.B. for other values, the counter channel's GATn + * pin on the SK1 connector is an output!) + * 3. /OUT n-2, the inverted output of counter channel n-2 (see note + * 2 below). + * 4. Reserved. + * 5. Reserved. + * 6. Reserved. + * 7. Reserved. + * + * For the PCIe boards, gate sources in the range 0 to 31 are allowed; + * the following additional clock sources and clock sources 6 and 7 are + * (re)defined: + * + * 6. /GAT n, negated version of the counter channel's dedicated + * GAT input (negated version of gate source 2). + * 7. OUT n-2, the non-inverted output of counter channel n-2 + * (negated version of gate source 3). + * 8. "Pattern present" signal, HIGH while pattern present. + * 9. "Pattern occurred" latched signal, latches HIGH when pattern + * occurs. + * 10. "Pattern gone away" latched signal, latches LOW when pattern + * goes away after it occurred. + * 11. Negated "pattern present" signal, LOW while pattern present + * (negated version of gate source 8). + * 12. Negated "pattern occurred" latched signal, latches LOW when + * pattern occurs (negated version of gate source 9). + * 13. Negated "pattern gone away" latched signal, latches LOW when + * pattern goes away after it occurred (negated version of gate + * source 10). + * + * INSN_CONFIG_GET_GATE_SRC. Returns the counter channel's current gate + * source in data[2]. + * + * Clock and gate interconnection notes: + * + * 1. Clock source OUT n-1 is the output of the preceding channel on the + * same counter subdevice if n > 0, or the output of channel 2 on the + * preceding counter subdevice (see note 3) if n = 0. + * + * 2. Gate source /OUT n-2 is the inverted output of channel 0 on the + * same counter subdevice if n = 2, or the inverted output of channel n+1 + * on the preceding counter subdevice (see note 3) if n < 2. + * + * 3. The counter subdevices are connected in a ring, so the highest + * counter subdevice precedes the lowest. + * + * The 'TIMER' subdevice is a free-running 32-bit timer subdevice. + * + * The 'INTERRUPT' subdevice pretends to be a digital input subdevice. The + * digital inputs come from the interrupt status register. The number of + * channels matches the number of interrupt sources. The PC214E does not + * have an interrupt status register; see notes on 'INTERRUPT SOURCES' + * below. + * + * INTERRUPT SOURCES + * + * PCI215 PCIe215 PCIe236 + * ------------- ------------- ------------- + * Sources 6 6 6 + * 0 PPI-X-C0 PPI-X-C0 PPI-X-C0 + * 1 PPI-X-C3 PPI-X-C3 PPI-X-C3 + * 2 PPI-Y-C0 PPI-Y-C0 unused + * 3 PPI-Y-C3 PPI-Y-C3 unused + * 4 CTR-Z1-OUT1 CTR-Z1-OUT1 CTR-Z1-OUT1 + * 5 CTR-Z2-OUT1 CTR-Z2-OUT1 CTR-Z2-OUT1 + * + * PCI272 PCIe296 + * ------------- ------------- + * Sources 6 6 + * 0 PPI-X-C0 PPI-X1-C0 + * 1 PPI-X-C3 PPI-X1-C3 + * 2 PPI-Y-C0 PPI-Y1-C0 + * 3 PPI-Y-C3 PPI-Y1-C3 + * 4 PPI-Z-C0 CTR-Z1-OUT1 + * 5 PPI-Z-C3 CTR-Z2-OUT1 + * + * When an interrupt source is enabled in the interrupt source enable + * register, a rising edge on the source signal latches the corresponding + * bit to 1 in the interrupt status register. + * + * When the interrupt status register value as a whole (actually, just the + * 6 least significant bits) goes from zero to non-zero, the board will + * generate an interrupt. The interrupt will remain asserted until the + * interrupt status register is cleared to zero. To clear a bit to zero in + * the interrupt status register, the corresponding interrupt source must + * be disabled in the interrupt source enable register (there is no + * separate interrupt clear register). + * + * COMMANDS + * + * The driver supports a read streaming acquisition command on the + * 'INTERRUPT' subdevice. The channel list selects the interrupt sources + * to be enabled. All channels will be sampled together (convert_src == + * TRIG_NOW). The scan begins a short time after the hardware interrupt + * occurs, subject to interrupt latencies (scan_begin_src == TRIG_EXT, + * scan_begin_arg == 0). The value read from the interrupt status register + * is packed into a short value, one bit per requested channel, in the + * order they appear in the channel list. + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/interrupt.h> + +#include "../comedidev.h" + +#include "amplc_dio200.h" + +/* PCI IDs */ +#define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a +#define PCI_DEVICE_ID_AMPLICON_PCI215 0x000b +#define PCI_DEVICE_ID_AMPLICON_PCIE236 0x0011 +#define PCI_DEVICE_ID_AMPLICON_PCIE215 0x0012 +#define PCI_DEVICE_ID_AMPLICON_PCIE296 0x0014 + +/* + * Board descriptions. + */ + +enum dio200_pci_model { + pci215_model, + pci272_model, + pcie215_model, + pcie236_model, + pcie296_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, + }, + }, + [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, + }, + }, + [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, + }, + }, + [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, + }, + }, + [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, + }, + }, +}; + +/* + * This function does some special set-up for the PCIe boards + * PCIe215, PCIe236, PCIe296. + */ +static int dio200_pcie_board_setup(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + void __iomem *brbase; + + /* + * The board uses Altera Cyclone IV with PCI-Express hard IP. + * The FPGA configuration has the PCI-Express Avalon-MM Bridge + * Control registers in PCI BAR 0, offset 0, and the length of + * these registers is 0x4000. + * + * We need to write 0x80 to the "Avalon-MM to PCI-Express Interrupt + * Enable" register at offset 0x50 to allow generation of PCIe + * interrupts when RXmlrq_i is asserted in the SOPC Builder system. + */ + if (pci_resource_len(pcidev, 0) < 0x4000) { + dev_err(dev->class_dev, "error! bad PCI region!\n"); + return -EINVAL; + } + brbase = pci_ioremap_bar(pcidev, 0); + if (!brbase) { + dev_err(dev->class_dev, "error! failed to map registers!\n"); + return -ENOMEM; + } + writel(0x80, brbase + 0x50); + iounmap(brbase); + /* Enable "enhanced" features of board. */ + amplc_dio200_set_enhance(dev, 1); + return 0; +} + +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; + unsigned int bar; + int ret; + + if (context_model < ARRAY_SIZE(dio200_pci_boards)) + thisboard = &dio200_pci_boards[context_model]; + if (!thisboard) + return -EINVAL; + dev->board_ptr = thisboard; + dev->board_name = thisboard->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; + } + if (pci_resource_flags(pci_dev, bar) & IORESOURCE_MEM) { + devpriv->io.u.membase = pci_ioremap_bar(pci_dev, bar); + if (!devpriv->io.u.membase) { + dev_err(dev->class_dev, + "error! cannot remap registers\n"); + return -ENOMEM; + } + devpriv->io.regtype = mmio_regtype; + } else { + devpriv->io.u.iobase = pci_resource_start(pci_dev, bar); + devpriv->io.regtype = io_regtype; + } + switch (context_model) { + case pcie215_model: + case pcie236_model: + case pcie296_model: + 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) +{ + const struct dio200_board *thisboard = comedi_board(dev); + struct dio200_private *devpriv = dev->private; + + if (!thisboard || !devpriv) + return; + amplc_dio200_common_detach(dev); + if (devpriv->io.regtype == mmio_regtype) + iounmap(devpriv->io.u.membase); + comedi_pci_disable(dev); +} + +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, +}; + +static const struct pci_device_id dio200_pci_table[] = { + { + PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215), + pci215_model + }, { + PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272), + pci272_model + }, { + PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE236), + pcie236_model + }, { + PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE215), + pcie215_model + }, { + PCI_VDEVICE(AMPLICON, PCI_DEVICE_ID_AMPLICON_PCIE296), + pcie296_model + }, + {0} +}; + +MODULE_DEVICE_TABLE(pci, dio200_pci_table); + +static int dio200_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &dio200_pci_comedi_driver, + id->driver_data); +} + +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, +}; +module_comedi_pci_driver(dio200_pci_comedi_driver, dio200_pci_pci_driver); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi driver for Amplicon 200 Series PCI(e) DIO boards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index 48246cd50d4..c9a96ad0055 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: amplc_pc236 @@ -52,19 +47,22 @@ the IRQ jumper. If no interrupt is connected, then subdevice 1 is unused. */ +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include "comedi_pci.h" - +#include "comedi_fc.h" #include "8255.h" #include "plx9052.h" #define PC236_DRIVER_NAME "amplc_pc236" +#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) +#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) + /* PCI236 PCI configuration register information */ -#define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009 #define PCI_DEVICE_ID_INVALID 0xffff @@ -73,23 +71,19 @@ unused. #define PC236_IO_SIZE 4 #define PC236_LCR_IO_SIZE 128 -/* - * INTCSR values for PCI236. - */ -/* Disable interrupt, also clear any interrupt there */ -#define PCI236_INTR_DISABLE (PLX9052_INTCSR_LI1ENAB_DISABLED \ - | PLX9052_INTCSR_LI1POL_HIGH \ - | PLX9052_INTCSR_LI2POL_HIGH \ - | PLX9052_INTCSR_PCIENAB_DISABLED \ - | PLX9052_INTCSR_LI1SEL_EDGE \ - | PLX9052_INTCSR_LI1CLRINT_ASSERTED) -/* Enable interrupt, also clear any interrupt there. */ -#define PCI236_INTR_ENABLE (PLX9052_INTCSR_LI1ENAB_ENABLED \ - | PLX9052_INTCSR_LI1POL_HIGH \ - | PLX9052_INTCSR_LI2POL_HIGH \ - | PLX9052_INTCSR_PCIENAB_ENABLED \ - | PLX9052_INTCSR_LI1SEL_EDGE \ - | PLX9052_INTCSR_LI1CLRINT_ASSERTED) +/* Disable, and clear, interrupts */ +#define PCI236_INTR_DISABLE (PLX9052_INTCSR_LI1POL | \ + PLX9052_INTCSR_LI2POL | \ + PLX9052_INTCSR_LI1SEL | \ + PLX9052_INTCSR_LI1CLRINT) + +/* Enable, and clear, interrupts */ +#define PCI236_INTR_ENABLE (PLX9052_INTCSR_LI1ENAB | \ + PLX9052_INTCSR_LI1POL | \ + PLX9052_INTCSR_LI2POL | \ + PLX9052_INTCSR_PCIENAB | \ + PLX9052_INTCSR_LI1SEL | \ + PLX9052_INTCSR_LI1CLRINT) /* * Board descriptions for Amplicon PC36AT and PCI236. @@ -100,416 +94,110 @@ enum pc236_model { pc36at_model, pci236_model, anypci_model }; struct pc236_board { const char *name; - const char *fancy_name; unsigned short devid; enum pc236_bustype bustype; enum pc236_model model; }; static const struct pc236_board pc236_boards[] = { +#if DO_ISA { - .name = "pc36at", - .fancy_name = "PC36AT", - .bustype = isa_bustype, - .model = pc36at_model, - }, -#ifdef CONFIG_COMEDI_PCI - { - .name = "pci236", - .fancy_name = "PCI236", - .devid = PCI_DEVICE_ID_AMPLICON_PCI236, - .bustype = pci_bustype, - .model = pci236_model, - }, + .name = "pc36at", + .bustype = isa_bustype, + .model = pc36at_model, + }, #endif -#ifdef CONFIG_COMEDI_PCI +#if DO_PCI { - .name = PC236_DRIVER_NAME, - .fancy_name = PC236_DRIVER_NAME, - .devid = PCI_DEVICE_ID_INVALID, - .bustype = pci_bustype, - .model = anypci_model, /* wildcard */ - }, -#endif -}; - -#ifdef CONFIG_COMEDI_PCI -static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = { + .name = "pci236", + .devid = PCI_DEVICE_ID_AMPLICON_PCI236, + .bustype = pci_bustype, + .model = pci236_model, + }, { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} + .name = PC236_DRIVER_NAME, + .devid = PCI_DEVICE_ID_INVALID, + .bustype = pci_bustype, + .model = anypci_model, /* wildcard */ + }, +#endif }; -MODULE_DEVICE_TABLE(pci, pc236_pci_table); -#endif /* CONFIG_COMEDI_PCI */ - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct pc236_board *)dev->board_ptr) - /* 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 pc236_private { -#ifdef CONFIG_COMEDI_PCI - /* PCI device */ - struct pci_dev *pci_dev; unsigned long lcr_iobase; /* PLX PCI9052 config registers in PCIBAR1 */ -#endif int enable_irq; }; -#define devpriv ((struct pc236_private *)dev->private) - -/* - * 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 int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int pc236_detach(struct comedi_device *dev); -static struct comedi_driver driver_amplc_pc236 = { - .driver_name = PC236_DRIVER_NAME, - .module = THIS_MODULE, - .attach = pc236_attach, - .detach = pc236_detach, - .board_name = &pc236_boards[0].name, - .offset = sizeof(struct pc236_board), - .num_names = ARRAY_SIZE(pc236_boards), -}; - -#ifdef CONFIG_COMEDI_PCI -static int __devinit driver_amplc_pc236_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +/* test if ISA supported and this is an ISA board */ +static inline bool is_isa_board(const struct pc236_board *board) { - return comedi_pci_auto_config(dev, driver_amplc_pc236.driver_name); + return DO_ISA && board->bustype == isa_bustype; } -static void __devexit driver_amplc_pc236_pci_remove(struct pci_dev *dev) +/* test if PCI supported and this is a PCI board */ +static inline bool is_pci_board(const struct pc236_board *board) { - comedi_pci_auto_unconfig(dev); + return DO_PCI && board->bustype == pci_bustype; } -static struct pci_driver driver_amplc_pc236_pci_driver = { - .id_table = pc236_pci_table, - .probe = &driver_amplc_pc236_pci_probe, - .remove = __devexit_p(&driver_amplc_pc236_pci_remove) -}; - -static int __init driver_amplc_pc236_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_amplc_pc236); - if (retval < 0) - return retval; - - driver_amplc_pc236_pci_driver.name = - (char *)driver_amplc_pc236.driver_name; - return pci_register_driver(&driver_amplc_pc236_pci_driver); -} - -static void __exit driver_amplc_pc236_cleanup_module(void) -{ - pci_unregister_driver(&driver_amplc_pc236_pci_driver); - comedi_driver_unregister(&driver_amplc_pc236); -} - -module_init(driver_amplc_pc236_init_module); -module_exit(driver_amplc_pc236_cleanup_module); -#else -static int __init driver_amplc_pc236_init_module(void) +/* + * This function looks for a board matching the supplied PCI device. + */ +static const struct pc236_board *pc236_find_pci_board(struct pci_dev *pci_dev) { - return comedi_driver_register(&driver_amplc_pc236); -} + unsigned int i; -static void __exit driver_amplc_pc236_cleanup_module(void) -{ - comedi_driver_unregister(&driver_amplc_pc236); + for (i = 0; i < ARRAY_SIZE(pc236_boards); i++) + if (is_pci_board(&pc236_boards[i]) && + pci_dev->device == pc236_boards[i].devid) + return &pc236_boards[i]; + return NULL; } -module_init(driver_amplc_pc236_init_module); -module_exit(driver_amplc_pc236_cleanup_module); -#endif - -static int pc236_request_region(unsigned minor, unsigned long from, - unsigned long extent); -static void pc236_intr_disable(struct comedi_device *dev); -static void pc236_intr_enable(struct comedi_device *dev); -static int pc236_intr_check(struct comedi_device *dev); -static int pc236_intr_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int pc236_intr_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int pc236_intr_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int pc236_intr_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static irqreturn_t pc236_interrupt(int irq, void *d); - /* * This function looks for a PCI device matching the requested board name, * bus and slot. */ -#ifdef CONFIG_COMEDI_PCI -static int -pc236_find_pci(struct comedi_device *dev, int bus, int slot, - struct pci_dev **pci_dev_p) +static struct pci_dev *pc236_find_pci_dev(struct comedi_device *dev, + struct comedi_devconfig *it) { + const struct pc236_board *thisboard = comedi_board(dev); struct pci_dev *pci_dev = NULL; + int bus = it->options[0]; + int slot = it->options[1]; - *pci_dev_p = NULL; - - /* Look for matching PCI device. */ - for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL); - pci_dev != NULL; - pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, - PCI_ANY_ID, pci_dev)) { - /* If bus/slot specified, check them. */ + for_each_pci_dev(pci_dev) { if (bus || slot) { - if (bus != pci_dev->bus->number - || slot != PCI_SLOT(pci_dev->devfn)) + 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 == anypci_model) { - /* Match any supported model. */ - int i; - - for (i = 0; i < ARRAY_SIZE(pc236_boards); i++) { - if (pc236_boards[i].bustype != pci_bustype) - continue; - if (pci_dev->device == pc236_boards[i].devid) { - /* Change board_ptr to matched board. */ - dev->board_ptr = &pc236_boards[i]; - break; - } - } - if (i == ARRAY_SIZE(pc236_boards)) + /* Wildcard board matches any supported PCI board. */ + const struct pc236_board *foundboard; + + foundboard = pc236_find_pci_board(pci_dev); + if (foundboard == NULL) continue; + /* Replace wildcard board_ptr. */ + dev->board_ptr = foundboard; } else { /* Match specific model name. */ if (pci_dev->device != thisboard->devid) continue; } - - /* Found a match. */ - *pci_dev_p = pci_dev; - return 0; - } - /* No match found. */ - if (bus || slot) { - printk(KERN_ERR - "comedi%d: error! no %s found at pci %02x:%02x!\n", - dev->minor, thisboard->name, bus, slot); - } else { - printk(KERN_ERR "comedi%d: error! no %s found!\n", - dev->minor, thisboard->name); - } - return -EIO; -} -#endif - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase = 0; - unsigned int irq = 0; -#ifdef CONFIG_COMEDI_PCI - struct pci_dev *pci_dev = NULL; - int bus = 0, slot = 0; -#endif - int share_irq = 0; - int ret; - - printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, - PC236_DRIVER_NAME); -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - ret = alloc_private(dev, sizeof(struct pc236_private)); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); - return ret; - } - /* Process options. */ - switch (thisboard->bustype) { - case isa_bustype: - iobase = it->options[0]; - irq = it->options[1]; - share_irq = 0; - break; -#ifdef CONFIG_COMEDI_PCI - case pci_bustype: - bus = it->options[0]; - slot = it->options[1]; - share_irq = 1; - - ret = pc236_find_pci(dev, bus, slot, &pci_dev); - if (ret < 0) - return ret; - devpriv->pci_dev = pci_dev; - break; -#endif /* CONFIG_COMEDI_PCI */ - default: - printk(KERN_ERR - "comedi%d: %s: BUG! cannot determine board type!\n", - dev->minor, PC236_DRIVER_NAME); - return -EINVAL; - break; - } - -/* - * Initialize dev->board_name. - */ - dev->board_name = thisboard->name; - - /* Enable device and reserve I/O spaces. */ -#ifdef CONFIG_COMEDI_PCI - if (pci_dev) { - - ret = comedi_pci_enable(pci_dev, PC236_DRIVER_NAME); - if (ret < 0) { - printk(KERN_ERR - "comedi%d: error! cannot enable PCI device and request regions!\n", - dev->minor); - return ret; - } - devpriv->lcr_iobase = pci_resource_start(pci_dev, 1); - iobase = pci_resource_start(pci_dev, 2); - irq = pci_dev->irq; - } else -#endif - { - ret = pc236_request_region(dev->minor, iobase, PC236_IO_SIZE); - if (ret < 0) - return ret; - } - dev->iobase = iobase; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - ret = alloc_subdevices(dev, 2); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); - return ret; - } - - s = dev->subdevices + 0; - /* digital i/o subdevice (8255) */ - ret = subdev_8255_init(dev, s, NULL, iobase); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); - return ret; - } - s = dev->subdevices + 1; - dev->read_subdev = s; - s->type = COMEDI_SUBD_UNUSED; - pc236_intr_disable(dev); - if (irq) { - unsigned long flags = share_irq ? IRQF_SHARED : 0; - - if (request_irq(irq, pc236_interrupt, flags, - PC236_DRIVER_NAME, dev) >= 0) { - dev->irq = irq; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = 1; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = pc236_intr_insn; - s->do_cmdtest = pc236_intr_cmdtest; - s->do_cmd = pc236_intr_cmd; - s->cancel = pc236_intr_cancel; - } - } - printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name); - if (thisboard->bustype == isa_bustype) { - printk("(base %#lx) ", iobase); - } else { -#ifdef CONFIG_COMEDI_PCI - printk("(pci %s) ", pci_name(pci_dev)); -#endif - } - if (irq) - printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE")); - else - printk("(no irq) "); - - printk("attached\n"); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pc236_detach(struct comedi_device *dev) -{ - printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, - PC236_DRIVER_NAME); - if (devpriv) - pc236_intr_disable(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 0); - if (devpriv) { -#ifdef CONFIG_COMEDI_PCI - if (devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } else -#endif - { - if (dev->iobase) - release_region(dev->iobase, PC236_IO_SIZE); - } - } - if (dev->board_name) { - printk(KERN_INFO "comedi%d: %s removed\n", - dev->minor, dev->board_name); + return pci_dev; } - return 0; -} - -/* - * This function checks and requests an I/O region, reporting an error - * if there is a conflict. - */ -static int pc236_request_region(unsigned minor, unsigned long from, - unsigned long extent) -{ - if (!from || !request_region(from, extent, PC236_DRIVER_NAME)) { - printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n", - minor, from, extent); - return -EIO; - } - return 0; + dev_err(dev->class_dev, + "No supported board found! (req. bus %d, slot %d)\n", + bus, slot); + return NULL; } /* @@ -519,14 +207,14 @@ static int pc236_request_region(unsigned minor, unsigned long from, */ static void pc236_intr_disable(struct comedi_device *dev) { + const struct pc236_board *thisboard = comedi_board(dev); + struct pc236_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); devpriv->enable_irq = 0; -#ifdef CONFIG_COMEDI_PCI - if (devpriv->lcr_iobase) + if (is_pci_board(thisboard)) outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR); -#endif spin_unlock_irqrestore(&dev->spinlock, flags); } @@ -537,14 +225,14 @@ static void pc236_intr_disable(struct comedi_device *dev) */ static void pc236_intr_enable(struct comedi_device *dev) { + const struct pc236_board *thisboard = comedi_board(dev); + struct pc236_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); devpriv->enable_irq = 1; -#ifdef CONFIG_COMEDI_PCI - if (devpriv->lcr_iobase) + if (is_pci_board(thisboard)) outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR); -#endif spin_unlock_irqrestore(&dev->spinlock, flags); } @@ -557,17 +245,18 @@ static void pc236_intr_enable(struct comedi_device *dev) */ static int pc236_intr_check(struct comedi_device *dev) { + const struct pc236_board *thisboard = comedi_board(dev); + struct pc236_private *devpriv = dev->private; int retval = 0; unsigned long flags; + unsigned int intcsr; spin_lock_irqsave(&dev->spinlock, flags); if (devpriv->enable_irq) { retval = 1; -#ifdef CONFIG_COMEDI_PCI - if (devpriv->lcr_iobase) { - if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR) - & PLX9052_INTCSR_LI1STAT_MASK) - == PLX9052_INTCSR_LI1STAT_INACTIVE) { + if (is_pci_board(thisboard)) { + intcsr = inl(devpriv->lcr_iobase + PLX9052_INTCSR); + if (!(intcsr & PLX9052_INTCSR_LI1STAT)) { retval = 0; } else { /* Clear interrupt and keep it enabled. */ @@ -575,7 +264,6 @@ static int pc236_intr_check(struct comedi_device *dev) devpriv->lcr_iobase + PLX9052_INTCSR); } } -#endif } spin_unlock_irqrestore(&dev->spinlock, flags); @@ -591,7 +279,7 @@ static int pc236_intr_insn(struct comedi_device *dev, unsigned int *data) { data[1] = 0; - return 2; + return insn->n; } /* @@ -603,65 +291,31 @@ static int pc236_intr_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1 */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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 2: ignored */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: */ + /* Step 3: check it arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->scan_end_arg != 1) { - cmd->scan_end_arg = 1; - err++; - } - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + 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; @@ -702,18 +356,217 @@ static int pc236_intr_cancel(struct comedi_device *dev, static irqreturn_t pc236_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 1; + struct comedi_subdevice *s = dev->read_subdev; int handled; handled = pc236_intr_check(dev); if (dev->attached && handled) { - comedi_buf_put(s->async, 0); + comedi_buf_put(s, 0); s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); } return IRQ_RETVAL(handled); } +static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, + unsigned int irq, unsigned long req_irq_flags) +{ + const struct pc236_board *thisboard = comedi_board(dev); + struct comedi_subdevice *s; + int ret; + + dev->board_name = thisboard->name; + dev->iobase = iobase; + + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + + s = &dev->subdevices[0]; + /* digital i/o subdevice (8255) */ + ret = subdev_8255_init(dev, s, NULL, iobase); + if (ret) + return ret; + + s = &dev->subdevices[1]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_UNUSED; + pc236_intr_disable(dev); + if (irq) { + if (request_irq(irq, pc236_interrupt, req_irq_flags, + PC236_DRIVER_NAME, dev) >= 0) { + dev->irq = irq; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pc236_intr_insn; + s->len_chanlist = 1; + s->do_cmdtest = pc236_intr_cmdtest; + s->do_cmd = pc236_intr_cmd; + s->cancel = pc236_intr_cancel; + } + } + + return 0; +} + +static int pc236_pci_common_attach(struct comedi_device *dev, + struct pci_dev *pci_dev) +{ + struct pc236_private *devpriv = dev->private; + unsigned long iobase; + int ret; + + comedi_set_hw_dev(dev, &pci_dev->dev); + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + devpriv->lcr_iobase = pci_resource_start(pci_dev, 1); + iobase = pci_resource_start(pci_dev, 2); + return pc236_common_attach(dev, iobase, pci_dev->irq, IRQF_SHARED); +} + +/* + * Attach is called by the Comedi core to configure the driver + * for a particular board. If you specified a board_name array + * in the driver structure, dev->board_ptr contains that + * address. + */ +static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + const struct pc236_board *thisboard = comedi_board(dev); + struct pc236_private *devpriv; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + /* Process options according to bus type. */ + if (is_isa_board(thisboard)) { + ret = comedi_request_region(dev, it->options[0], PC236_IO_SIZE); + if (ret) + return ret; + + return pc236_common_attach(dev, dev->iobase, it->options[1], 0); + } else if (is_pci_board(thisboard)) { + struct pci_dev *pci_dev; + + pci_dev = pc236_find_pci_dev(dev, it); + if (!pci_dev) + return -EIO; + return pc236_pci_common_attach(dev, pci_dev); + } else { + dev_err(dev->class_dev, PC236_DRIVER_NAME + ": BUG! cannot determine board type!\n"); + return -EINVAL; + } +} + +/* + * The auto_attach hook is called at PCI probe time via + * comedi_pci_auto_config(). dev->board_ptr is NULL on entry. + * There should be a board entry matching the supplied PCI device. + */ +static int pc236_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pci_dev = comedi_to_pci_dev(dev); + struct pc236_private *devpriv; + + if (!DO_PCI) + return -EINVAL; + + dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach pci %s\n", + pci_name(pci_dev)); + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + dev->board_ptr = pc236_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 pc236_detach(). + * TODO: Remove the pci_dev_get() and matching pci_dev_put() once + * support for manual attachment of PCI devices via pc236_attach() + * has been removed. + */ + pci_dev_get(pci_dev); + return pc236_pci_common_attach(dev, pci_dev); +} + +static void pc236_detach(struct comedi_device *dev) +{ + const struct pc236_board *thisboard = comedi_board(dev); + + if (!thisboard) + return; + if (dev->iobase) + pc236_intr_disable(dev); + if (is_isa_board(thisboard)) { + comedi_legacy_detach(dev); + } else if (is_pci_board(thisboard)) { + 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); + } +} + +/* + * 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 amplc_pc236_driver = { + .driver_name = PC236_DRIVER_NAME, + .module = THIS_MODULE, + .attach = pc236_attach, + .auto_attach = pc236_auto_attach, + .detach = pc236_detach, + .board_name = &pc236_boards[0].name, + .offset = sizeof(struct pc236_board), + .num_names = ARRAY_SIZE(pc236_boards), +}; + +#if DO_PCI +static const struct pci_device_id pc236_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) }, + {0} +}; + +MODULE_DEVICE_TABLE(pci, pc236_pci_table); + +static int amplc_pc236_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &lc_pc236_driver, + id->driver_data); +} + +static struct pci_driver amplc_pc236_pci_driver = { + .name = PC236_DRIVER_NAME, + .id_table = pc236_pci_table, + .probe = &lc_pc236_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; + +module_comedi_pci_driver(amplc_pc236_driver, amplc_pc236_pci_driver); +#else +module_comedi_driver(amplc_pc236_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/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 8a338807909..7c10d28d278 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -16,476 +16,99 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: amplc_pc263 -Description: Amplicon PC263, PCI263 +Description: Amplicon PC263 Author: Ian Abbott <abbotti@mev.co.uk> -Devices: [Amplicon] PC263 (pc263), PCI263 (pci263 or amplc_pc263) -Updated: Wed, 22 Oct 2008 14:10:53 +0100 +Devices: [Amplicon] PC263 (pc263) +Updated: Fri, 12 Apr 2013 15:19:36 +0100 Status: works -Configuration options - PC263: +Configuration options: [0] - I/O port base address -Configuration options - PCI263: - [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. - -Each board appears as one subdevice, with 16 digital outputs, each +The board appears as one subdevice, with 16 digital outputs, each connected to a reed-relay. Relay contacts are closed when output is 1. The state of the outputs can be read. */ +#include <linux/module.h> #include "../comedidev.h" -#include "comedi_pci.h" - #define PC263_DRIVER_NAME "amplc_pc263" -/* PCI263 PCI configuration register information */ -#define PCI_VENDOR_ID_AMPLICON 0x14dc -#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c -#define PCI_DEVICE_ID_INVALID 0xffff - -/* PC263 / PCI263 registers */ +/* PC263 registers */ #define PC263_IO_SIZE 2 /* - * Board descriptions for Amplicon PC263 / PCI263. + * Board descriptions for Amplicon PC263. */ -enum pc263_bustype { isa_bustype, pci_bustype }; -enum pc263_model { pc263_model, pci263_model, anypci_model }; - struct pc263_board { const char *name; - const char *fancy_name; - unsigned short devid; - enum pc263_bustype bustype; - enum pc263_model model; -}; -static const struct pc263_board pc263_boards[] = { - { - .name = "pc263", - .fancy_name = "PC263", - .bustype = isa_bustype, - .model = pc263_model, - }, -#ifdef CONFIG_COMEDI_PCI - { - .name = "pci263", - .fancy_name = "PCI263", - .devid = PCI_DEVICE_ID_AMPLICON_PCI263, - .bustype = pci_bustype, - .model = pci263_model, - }, -#endif -#ifdef CONFIG_COMEDI_PCI - { - .name = PC263_DRIVER_NAME, - .fancy_name = PC263_DRIVER_NAME, - .devid = PCI_DEVICE_ID_INVALID, - .bustype = pci_bustype, - .model = anypci_model, /* wildcard */ - }, -#endif }; -#ifdef CONFIG_COMEDI_PCI -static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = { +static const struct pc263_board pc263_boards[] = { { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, pc263_pci_table); -#endif /* CONFIG_COMEDI_PCI */ - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct pc263_board *)dev->board_ptr) - -/* 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. -*/ -#ifdef CONFIG_COMEDI_PCI -struct pc263_private { - /* PCI device. */ - struct pci_dev *pci_dev; -}; - -#define devpriv ((struct pc263_private *)dev->private) -#endif /* CONFIG_COMEDI_PCI */ - -/* - * 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 int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int pc263_detach(struct comedi_device *dev); -static struct comedi_driver driver_amplc_pc263 = { - .driver_name = PC263_DRIVER_NAME, - .module = THIS_MODULE, - .attach = pc263_attach, - .detach = pc263_detach, - .board_name = &pc263_boards[0].name, - .offset = sizeof(struct pc263_board), - .num_names = ARRAY_SIZE(pc263_boards), + .name = "pc263", + }, }; -static int pc263_request_region(unsigned minor, unsigned long from, - unsigned long extent); -static int pc263_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pc263_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * This function looks for a PCI device matching the requested board name, - * bus and slot. - */ -#ifdef CONFIG_COMEDI_PCI -static int -pc263_find_pci(struct comedi_device *dev, int bus, int slot, - struct pci_dev **pci_dev_p) +static int pc263_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct pci_dev *pci_dev = NULL; - - *pci_dev_p = NULL; - - /* Look for matching PCI device. */ - for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL); - pci_dev != NULL; - pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, - PCI_ANY_ID, pci_dev)) { - /* If bus/slot specified, check them. */ - if (bus || slot) { - if (bus != pci_dev->bus->number - || slot != PCI_SLOT(pci_dev->devfn)) - continue; - } - if (thisboard->model == anypci_model) { - /* Match any supported model. */ - int i; + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase); + outb((s->state >> 8) & 0xff, dev->iobase + 1); + } - for (i = 0; i < ARRAY_SIZE(pc263_boards); i++) { - if (pc263_boards[i].bustype != pci_bustype) - continue; - if (pci_dev->device == pc263_boards[i].devid) { - /* Change board_ptr to matched board. */ - dev->board_ptr = &pc263_boards[i]; - break; - } - } - if (i == ARRAY_SIZE(pc263_boards)) - continue; - } else { - /* Match specific model name. */ - if (pci_dev->device != thisboard->devid) - continue; - } + data[1] = s->state; - /* Found a match. */ - *pci_dev_p = pci_dev; - return 0; - } - /* No match found. */ - if (bus || slot) { - printk(KERN_ERR - "comedi%d: error! no %s found at pci %02x:%02x!\n", - dev->minor, thisboard->name, bus, slot); - } else { - printk(KERN_ERR "comedi%d: error! no %s found!\n", - dev->minor, thisboard->name); - } - return -EIO; + return insn->n; } -#endif -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) { struct comedi_subdevice *s; - unsigned long iobase = 0; -#ifdef CONFIG_COMEDI_PCI - struct pci_dev *pci_dev = NULL; - int bus = 0, slot = 0; -#endif int ret; - printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, - PC263_DRIVER_NAME); -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ -#ifdef CONFIG_COMEDI_PCI - ret = alloc_private(dev, sizeof(struct pc263_private)); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); + ret = comedi_request_region(dev, it->options[0], PC263_IO_SIZE); + if (ret) return ret; - } -#endif - /* Process options. */ - switch (thisboard->bustype) { - case isa_bustype: - iobase = it->options[0]; - break; -#ifdef CONFIG_COMEDI_PCI - case pci_bustype: - bus = it->options[0]; - slot = it->options[1]; - - ret = pc263_find_pci(dev, bus, slot, &pci_dev); - if (ret < 0) - return ret; - devpriv->pci_dev = pci_dev; - break; -#endif /* CONFIG_COMEDI_PCI */ - default: - printk(KERN_ERR - "comedi%d: %s: BUG! cannot determine board type!\n", - dev->minor, PC263_DRIVER_NAME); - return -EINVAL; - break; - } - -/* - * Initialize dev->board_name. - */ - dev->board_name = thisboard->name; - /* Enable device and reserve I/O spaces. */ -#ifdef CONFIG_COMEDI_PCI - if (pci_dev) { - ret = comedi_pci_enable(pci_dev, PC263_DRIVER_NAME); - if (ret < 0) { - printk(KERN_ERR - "comedi%d: error! cannot enable PCI device and " - "request regions!\n", - dev->minor); - return ret; - } - iobase = pci_resource_start(pci_dev, 2); - } else -#endif - { - ret = pc263_request_region(dev->minor, iobase, PC263_IO_SIZE); - if (ret < 0) - return ret; - } - dev->iobase = iobase; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - ret = alloc_subdevices(dev, 1); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); + ret = comedi_alloc_subdevices(dev, 1); + if (ret) return ret; - } - s = dev->subdevices + 0; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; + s = &dev->subdevices[0]; + /* digital output subdevice */ + s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; - s->insn_bits = pc263_dio_insn_bits; - s->insn_config = pc263_dio_insn_config; - /* all outputs */ - s->io_bits = 0xffff; + s->insn_bits = pc263_do_insn_bits; /* read initial relay state */ - s->state = inb(dev->iobase); - s->state = s->state | (inb(dev->iobase) << 8); - - printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name); - if (thisboard->bustype == isa_bustype) { - printk("(base %#lx) ", iobase); - } else { -#ifdef CONFIG_COMEDI_PCI - printk("(pci %s) ", pci_name(pci_dev)); -#endif - } - - printk("attached\n"); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pc263_detach(struct comedi_device *dev) -{ - printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, - PC263_DRIVER_NAME); + s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); -#ifdef CONFIG_COMEDI_PCI - if (devpriv) { -#endif -#ifdef CONFIG_COMEDI_PCI - if (devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } else -#endif - { - if (dev->iobase) - release_region(dev->iobase, PC263_IO_SIZE); - } - } - if (dev->board_name) { - printk(KERN_INFO "comedi%d: %s removed\n", - dev->minor, dev->board_name); - } - return 0; -} - -/* - * This function checks and requests an I/O region, reporting an error - * if there is a conflict. - */ -static int pc263_request_region(unsigned minor, unsigned long from, - unsigned long extent) -{ - if (!from || !request_region(from, extent, PC263_DRIVER_NAME)) { - printk(KERN_ERR "comedi%d: I/O port conflict (%#lx,%lu)!\n", - minor, from, extent); - return -EIO; - } return 0; } -/* 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 pc263_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - outb(s->state & 0xFF, dev->iobase); - outb(s->state >> 8, dev->iobase + 1); - } - - /* on return, data[1] contains the value of the digital - * input and output lines. */ - /* 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 2; -} - -static int pc263_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 1) - return -EINVAL; - return 1; -} - -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -#ifdef CONFIG_COMEDI_PCI -static int __devinit driver_amplc_pc263_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_amplc_pc263.driver_name); -} - -static void __devexit driver_amplc_pc263_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_amplc_pc263_pci_driver = { - .id_table = pc263_pci_table, - .probe = &driver_amplc_pc263_pci_probe, - .remove = __devexit_p(&driver_amplc_pc263_pci_remove) +static struct comedi_driver amplc_pc263_driver = { + .driver_name = PC263_DRIVER_NAME, + .module = THIS_MODULE, + .attach = pc263_attach, + .detach = comedi_legacy_detach, + .board_name = &pc263_boards[0].name, + .offset = sizeof(struct pc263_board), + .num_names = ARRAY_SIZE(pc263_boards), }; -static int __init driver_amplc_pc263_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_amplc_pc263); - if (retval < 0) - return retval; - - driver_amplc_pc263_pci_driver.name = - (char *)driver_amplc_pc263.driver_name; - return pci_register_driver(&driver_amplc_pc263_pci_driver); -} - -static void __exit driver_amplc_pc263_cleanup_module(void) -{ - pci_unregister_driver(&driver_amplc_pc263_pci_driver); - comedi_driver_unregister(&driver_amplc_pc263); -} - -module_init(driver_amplc_pc263_init_module); -module_exit(driver_amplc_pc263_cleanup_module); -#else -static int __init driver_amplc_pc263_init_module(void) -{ - return comedi_driver_register(&driver_amplc_pc263); -} - -static void __exit driver_amplc_pc263_cleanup_module(void) -{ - comedi_driver_unregister(&driver_amplc_pc263); -} - -module_init(driver_amplc_pc263_init_module); -module_exit(driver_amplc_pc263_cleanup_module); -#endif +module_comedi_driver(amplc_pc263_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Amplicon PC263 relay board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 1b5ba1c2725..339c47c1eb9 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: amplc_pci224 @@ -103,13 +98,13 @@ Caveats: correctly. */ +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/slab.h> #include "../comedidev.h" -#include "comedi_pci.h" - #include "comedi_fc.h" #include "8253.h" @@ -118,7 +113,6 @@ Caveats: /* * PCI IDs. */ -#define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_AMPLICON_PCI224 0x0007 #define PCI_DEVICE_ID_AMPLICON_PCI234 0x0008 #define PCI_DEVICE_ID_INVALID 0xffff @@ -221,12 +215,6 @@ Caveats: #define CLK_EXT 7 /* external clock */ /* Macro to construct clock input configuration register value. */ #define CLK_CONFIG(chan, src) ((((chan) & 3) << 3) | ((src) & 7)) -/* Timebases in ns. */ -#define TIMEBASE_10MHZ 100 -#define TIMEBASE_1MHZ 1000 -#define TIMEBASE_100KHZ 10000 -#define TIMEBASE_10KHZ 100000 -#define TIMEBASE_1KHZ 1000000 /* * Counter/timer gate input configuration sources. @@ -267,9 +255,6 @@ Caveats: /* Combine old and new bits. */ #define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask))) -/* A generic null function pointer value. */ -#define NULLFUNC 0 - /* Current CPU. XXX should this be hard_smp_processor_id()? */ #define THISCPU smp_processor_id() @@ -282,17 +267,16 @@ Caveats: /* The software selectable internal ranges for PCI224 (option[2] == 0). */ static const struct comedi_lrange range_pci224_internal = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; static const unsigned short hwrange_pci224_internal[8] = { @@ -308,11 +292,10 @@ static const unsigned short hwrange_pci224_internal[8] = { /* The software selectable external ranges for PCI224 (option[2] == 1). */ static const struct comedi_lrange range_pci224_external = { - 2, - { - RANGE_ext(-1, 1), /* bipolar [-Vref,+Vref] */ - RANGE_ext(0, 1), /* unipolar [0,+Vref] */ - } + 2, { + RANGE_ext(-1, 1), /* bipolar [-Vref,+Vref] */ + RANGE_ext(0, 1) /* unipolar [0,+Vref] */ + } }; static const unsigned short hwrange_pci224_external[2] = { @@ -323,19 +306,17 @@ static const unsigned short hwrange_pci224_external[2] = { /* The hardware selectable Vref*2 external range for PCI234 * (option[2] == 1, option[3+n] == 0). */ static const struct comedi_lrange range_pci234_ext2 = { - 1, - { - RANGE_ext(-2, 2), - } + 1, { + RANGE_ext(-2, 2) + } }; /* The hardware selectable Vref external range for PCI234 * (option[2] == 1, option[3+n] == 1). */ static const struct comedi_lrange range_pci234_ext = { - 1, - { - RANGE_ext(-1, 1), - } + 1, { + RANGE_ext(-1, 1) + } }; /* This serves for all the PCI234 ranges. */ @@ -379,37 +360,16 @@ static const struct pci224_board pci224_boards[] = { }, }; -/* - * PCI driver table. - */ - -static DEFINE_PCI_DEVICE_TABLE(pci224_pci_table) = { - { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, pci224_pci_table); - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((struct pci224_board *)dev->board_ptr) - /* 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 { - struct pci_dev *pci_dev; /* PCI device */ const unsigned short *hwrange; unsigned long iobase1; unsigned long state; spinlock_t ao_spinlock; unsigned int *ao_readback; - short *ao_scan_vals; + unsigned short *ao_scan_vals; unsigned char *ao_scan_order; int intr_cpuid; short intr_running; @@ -417,72 +377,10 @@ struct pci224_private { unsigned int cached_div1; unsigned int cached_div2; unsigned int ao_stop_count; - short ao_stop_continuous; unsigned short ao_enab; /* max 16 channels so 'short' will do */ unsigned char intsce; }; -#define devpriv ((struct pci224_private *)dev->private) - -/* - * 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 int pci224_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci224_detach(struct comedi_device *dev); -static struct comedi_driver driver_amplc_pci224 = { - .driver_name = DRIVER_NAME, - .module = THIS_MODULE, - .attach = pci224_attach, - .detach = pci224_detach, - .board_name = &pci224_boards[0].name, - .offset = sizeof(struct pci224_board), - .num_names = ARRAY_SIZE(pci224_boards), -}; - -static int __devinit driver_amplc_pci224_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_amplc_pci224.driver_name); -} - -static void __devexit driver_amplc_pci224_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_amplc_pci224_pci_driver = { - .id_table = pci224_pci_table, - .probe = &driver_amplc_pci224_pci_probe, - .remove = __devexit_p(&driver_amplc_pci224_pci_remove) -}; - -static int __init driver_amplc_pci224_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_amplc_pci224); - if (retval < 0) - return retval; - - driver_amplc_pci224_pci_driver.name = - (char *)driver_amplc_pci224.driver_name; - return pci_register_driver(&driver_amplc_pci224_pci_driver); -} - -static void __exit driver_amplc_pci224_cleanup_module(void) -{ - pci_unregister_driver(&driver_amplc_pci224_pci_driver); - comedi_driver_unregister(&driver_amplc_pci224); -} - -module_init(driver_amplc_pci224_init_module); -module_exit(driver_amplc_pci224_cleanup_module); - /* * Called from the 'insn_write' function to perform a single write. */ @@ -490,6 +388,8 @@ 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); + struct pci224_private *devpriv = dev->private; unsigned short mangled; /* Store unmangled data for readback. */ @@ -552,6 +452,7 @@ 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; @@ -565,21 +466,12 @@ pci224_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, } /* - * Just a wrapper for the inline function 'i8253_cascade_ns_to_timer'. - */ -static void -pci224_cascade_ns_to_timer(int osc_base, unsigned int *d1, unsigned int *d2, - unsigned int *nanosec, int round_mode) -{ - i8253_cascade_ns_to_timer(osc_base, d1, d2, nanosec, round_mode); -} - -/* * Kills a command running on the AO subdevice. */ static void pci224_ao_stop(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci224_private *devpriv = dev->private; unsigned long flags; if (!test_and_clear_bit(AO_CMD_STARTED, &devpriv->state)) @@ -623,15 +515,15 @@ static void pci224_ao_stop(struct comedi_device *dev, static void pci224_ao_start(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci224_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; set_bit(AO_CMD_STARTED, &devpriv->state); - if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) { /* An empty acquisition! */ - pci224_ao_stop(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); } else { /* Enable interrupts. */ spin_lock_irqsave(&devpriv->ao_spinlock, flags); @@ -651,22 +543,17 @@ static void pci224_ao_start(struct comedi_device *dev, static void pci224_ao_handle_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci224_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int bytes_per_scan = cfc_bytes_per_scan(s); unsigned int num_scans; unsigned int room; unsigned short dacstat; unsigned int i, n; - unsigned int bytes_per_scan; - if (cmd->chanlist_len) { - bytes_per_scan = cmd->chanlist_len * sizeof(short); - } else { - /* Shouldn't get here! */ - bytes_per_scan = sizeof(short); - } /* Determine number of scans available in buffer. */ - num_scans = comedi_buf_read_n_available(s->async) / bytes_per_scan; - if (!devpriv->ao_stop_continuous) { + num_scans = comedi_buf_read_n_available(s) / bytes_per_scan; + if (cmd->stop_src == TRIG_COUNT) { /* Fixed number of scans. */ if (num_scans > devpriv->ao_stop_count) num_scans = devpriv->ao_stop_count; @@ -678,11 +565,10 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, switch (dacstat & PCI224_DACCON_FIFOFL_MASK) { case PCI224_DACCON_FIFOFL_EMPTY: room = PCI224_FIFO_ROOM_EMPTY; - if (!devpriv->ao_stop_continuous && devpriv->ao_stop_count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_stop_count == 0) { /* FIFO empty at end of counted acquisition. */ - pci224_ao_stop(dev, s); s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } break; @@ -700,15 +586,12 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, /* FIFO is less than half-full. */ if (num_scans == 0) { /* Nothing left to put in the FIFO. */ - pci224_ao_stop(dev, s); + dev_err(dev->class_dev, "AO buffer underrun\n"); s->async->events |= COMEDI_CB_OVERFLOW; - printk(KERN_ERR "comedi%d: " - "AO buffer underrun\n", dev->minor); } } /* Determine how many new scans can be put in the FIFO. */ - if (cmd->chanlist_len) - room /= cmd->chanlist_len; + room /= cmd->chanlist_len; /* Determine how many scans to process. */ if (num_scans > room) @@ -723,7 +606,7 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, dev->iobase + PCI224_DACDATA); } } - if (!devpriv->ao_stop_continuous) { + if (cmd->stop_src == TRIG_COUNT) { devpriv->ao_stop_count -= num_scans; if (devpriv->ao_stop_count == 0) { /* @@ -766,27 +649,56 @@ static void pci224_ao_handle_fifo(struct comedi_device *dev, PCI224_DACCON_TRIG_MASK); outw(devpriv->daccon, dev->iobase + PCI224_DACCON); } - if (s->async->events) - comedi_event(dev, s); + cfc_handle_events(dev, s); } -/* - * Internal trigger function to start acquisition on AO subdevice. - */ -static int -pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pci224_ao_inttrig_start(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; - s->async->inttrig = NULLFUNC; + s->async->inttrig = NULL; pci224_ao_start(dev, s); return 1; } +static int pci224_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + unsigned int chan_mask = 0; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan_mask & (1 << chan)) { + dev_dbg(dev->class_dev, + "%s: entries in chanlist must contain no duplicate channels\n", + __func__); + return -EINVAL; + } + chan_mask |= (1 << chan); + + if (range != range0) { + dev_dbg(dev->class_dev, + "%s: entries in chanlist must all have the same range index\n", + __func__); + return -EINVAL; + } + } + + return 0; +} + #define MAX_SCAN_PERIOD 0xFFFFFFFFU #define MIN_SCAN_PERIOD 2500 #define CONVERT_PERIOD 625 @@ -798,139 +710,100 @@ static int pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + struct pci224_private *devpriv = dev->private; int err = 0; - unsigned int tmp; + unsigned int arg; - /* Step 1: make sure trigger sources are trivially valid. */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + 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); + 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); - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT | TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + if (err) + return 1; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 2a : make sure trigger sources are unique */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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->stop_src); - if (err) - return 1; + /* Step 2b : and mutually compatible */ - /* Step 2: make sure trigger sources are unique and mutually - * compatible. */ - - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; - - /* There's only one external trigger signal (which makes these - * tests easier). Only one thing can use it. */ - tmp = 0; + /* + * There's only one external trigger signal (which makes these + * tests easier). Only one thing can use it. + */ + arg = 0; if (cmd->start_src & TRIG_EXT) - tmp++; + arg++; if (cmd->scan_begin_src & TRIG_EXT) - tmp++; + arg++; if (cmd->stop_src & TRIG_EXT) - tmp++; - if (tmp > 1) - err++; + arg++; + if (arg > 1) + err |= -EINVAL; if (err) return 2; - /* Step 3: make sure arguments are trivially compatible. */ + /* Step 3: check if arguments are trivially valid */ switch (cmd->start_src) { case TRIG_INT: - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 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); - err++; + err |= -EINVAL; } /* The only flag allowed is CR_EDGE, which is ignored. */ if ((cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) { cmd->start_arg = COMBINE(cmd->start_arg, 0, CR_FLAGS_MASK & ~CR_EDGE); - err++; + err |= -EINVAL; } break; } switch (cmd->scan_begin_src) { case TRIG_TIMER: - if (cmd->scan_begin_arg > MAX_SCAN_PERIOD) { - cmd->scan_begin_arg = MAX_SCAN_PERIOD; - err++; - } - tmp = cmd->chanlist_len * CONVERT_PERIOD; - if (tmp < MIN_SCAN_PERIOD) - tmp = MIN_SCAN_PERIOD; + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, + MAX_SCAN_PERIOD); - if (cmd->scan_begin_arg < tmp) { - cmd->scan_begin_arg = tmp; - err++; - } + arg = cmd->chanlist_len * CONVERT_PERIOD; + if (arg < MIN_SCAN_PERIOD) + arg = MIN_SCAN_PERIOD; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, arg); break; case TRIG_EXT: /* Force to external trigger 0. */ if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) { cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK); - err++; + 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)); - err++; + CR_FLAGS_MASK & + ~(CR_EDGE | CR_INVERT)); + err |= -EINVAL; } break; } - /* cmd->convert_src == TRIG_NOW */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - - /* cmd->scan_end_arg == TRIG_COUNT */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + 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: @@ -941,7 +814,7 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if ((cmd->stop_arg & ~CR_FLAGS_MASK) != 0) { cmd->stop_arg = COMBINE(cmd->stop_arg, 0, ~CR_FLAGS_MASK); - err++; + err |= -EINVAL; } /* The only flag allowed is CR_EDGE, which is ignored. */ if ((cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) { @@ -950,10 +823,7 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, } break; case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); break; } @@ -963,99 +833,21 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, /* Step 4: fix up any arguments. */ if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1, div2, round; - int round_mode = cmd->flags & TRIG_ROUND_MASK; - - tmp = cmd->scan_begin_arg; - /* Check whether to use a single timer. */ - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - round = TIMEBASE_10MHZ / 2; - break; - case TRIG_ROUND_DOWN: - round = 0; - break; - case TRIG_ROUND_UP: - round = TIMEBASE_10MHZ - 1; - break; - } - /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / TIMEBASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % TIMEBASE_10MHZ) / - TIMEBASE_10MHZ; - if (div2 <= 0x10000) { - /* A single timer will suffice. */ - if (div2 < 2) - div2 = 2; - cmd->scan_begin_arg = div2 * TIMEBASE_10MHZ; - if (cmd->scan_begin_arg < div2 || - cmd->scan_begin_arg < TIMEBASE_10MHZ) { - /* Overflow! */ - cmd->scan_begin_arg = MAX_SCAN_PERIOD; - } - } else { - /* Use two timers. */ - div1 = devpriv->cached_div1; - div2 = devpriv->cached_div2; - pci224_cascade_ns_to_timer(TIMEBASE_10MHZ, &div1, &div2, - &cmd->scan_begin_arg, - round_mode); - devpriv->cached_div1 = div1; - devpriv->cached_div2 = div2; - } - if (tmp != cmd->scan_begin_arg) - err++; - + arg = cmd->scan_begin_arg; + /* Use two timers. */ + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->cached_div1, + &devpriv->cached_div2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) return 4; - /* Step 5: check channel list. */ - - if (cmd->chanlist && (cmd->chanlist_len > 0)) { - unsigned int range; - enum { range_err = 1, dupchan_err = 2, }; - unsigned errors; - unsigned int n; - unsigned int ch; - - /* - * Check all channels have the same range index. Don't care - * about analogue reference, as we can't configure it. - * - * Check the list has no duplicate channels. - */ - range = CR_RANGE(cmd->chanlist[0]); - errors = 0; - tmp = 0; - for (n = 0; n < cmd->chanlist_len; n++) { - ch = CR_CHAN(cmd->chanlist[n]); - if (tmp & (1U << ch)) - errors |= dupchan_err; - - tmp |= (1U << ch); - if (CR_RANGE(cmd->chanlist[n]) != range) - errors |= range_err; - - } - if (errors) { - if (errors & dupchan_err) { - DPRINTK("comedi%d: " DRIVER_NAME - ": ao_cmdtest: " - "entries in chanlist must contain no " - "duplicate channels\n", dev->minor); - } - if (errors & range_err) { - DPRINTK("comedi%d: " DRIVER_NAME - ": ao_cmdtest: " - "entries in chanlist must all have " - "the same range index\n", dev->minor); - } - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci224_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1063,11 +855,36 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* - * 'do_cmd' function for AO subdevice. - */ +static void pci224_ao_start_pacer(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci224_private *devpriv = dev->private; + unsigned long timer_base = devpriv->iobase1 + PCI224_Z2_CT0; + + /* + * The output of timer Z2-0 will be used as the scan trigger + * source. + */ + /* Make sure Z2-0 is gated on. */ + outb(GAT_CONFIG(0, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE); + /* Cascading with Z2-2. */ + /* Make sure Z2-2 is gated on. */ + outb(GAT_CONFIG(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE); + /* Z2-2 needs 10 MHz clock. */ + outb(CLK_CONFIG(2, CLK_10MHZ), devpriv->iobase1 + PCI224_ZCLK_SCE); + /* Load Z2-2 mode (2) and counter (div1). */ + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 2, devpriv->cached_div1); + /* Z2-0 is clocked from Z2-2's output. */ + outb(CLK_CONFIG(0, CLK_OUTNM1), devpriv->iobase1 + PCI224_ZCLK_SCE); + /* Load Z2-0 mode (2) and counter (div2). */ + i8254_set_mode(timer_base, 0, 0, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 0, devpriv->cached_div2); +} + static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci224_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int range; unsigned int i, j; @@ -1120,105 +937,26 @@ static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1, div2, round; - unsigned int ns = cmd->scan_begin_arg; - int round_mode = cmd->flags & TRIG_ROUND_MASK; - - /* Check whether to use a single timer. */ - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - round = TIMEBASE_10MHZ / 2; - break; - case TRIG_ROUND_DOWN: - round = 0; - break; - case TRIG_ROUND_UP: - round = TIMEBASE_10MHZ - 1; - break; - } - /* Be careful to avoid overflow! */ - div2 = cmd->scan_begin_arg / TIMEBASE_10MHZ; - div2 += (round + cmd->scan_begin_arg % TIMEBASE_10MHZ) / - TIMEBASE_10MHZ; - if (div2 <= 0x10000) { - /* A single timer will suffice. */ - if (div2 < 2) - div2 = 2; - div2 &= 0xffff; - div1 = 1; /* Flag that single timer to be used. */ - } else { - /* Use two timers. */ - div1 = devpriv->cached_div1; - div2 = devpriv->cached_div2; - pci224_cascade_ns_to_timer(TIMEBASE_10MHZ, &div1, &div2, - &ns, round_mode); - } - - /* - * The output of timer Z2-0 will be used as the scan trigger - * source. - */ - /* Make sure Z2-0 is gated on. */ - outb(GAT_CONFIG(0, GAT_VCC), - devpriv->iobase1 + PCI224_ZGAT_SCE); - if (div1 == 1) { - /* Not cascading. Z2-0 needs 10 MHz clock. */ - outb(CLK_CONFIG(0, CLK_10MHZ), - devpriv->iobase1 + PCI224_ZCLK_SCE); - } else { - /* Cascading with Z2-2. */ - /* Make sure Z2-2 is gated on. */ - outb(GAT_CONFIG(2, GAT_VCC), - devpriv->iobase1 + PCI224_ZGAT_SCE); - /* Z2-2 needs 10 MHz clock. */ - outb(CLK_CONFIG(2, CLK_10MHZ), - devpriv->iobase1 + PCI224_ZCLK_SCE); - /* Load Z2-2 mode (2) and counter (div1). */ - i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0, - 2, div1, 2); - /* Z2-0 is clocked from Z2-2's output. */ - outb(CLK_CONFIG(0, CLK_OUTNM1), - devpriv->iobase1 + PCI224_ZCLK_SCE); - } - /* Load Z2-0 mode (2) and counter (div2). */ - i8254_load(devpriv->iobase1 + PCI224_Z2_CT0, 0, 0, div2, 2); - } + if (cmd->scan_begin_src == TRIG_TIMER) + pci224_ao_start_pacer(dev, s); /* * Sort out end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - /* Fixed number of scans. */ - devpriv->ao_stop_continuous = 0; + if (cmd->stop_src == TRIG_COUNT) devpriv->ao_stop_count = cmd->stop_arg; - break; - default: - /* Continuous scans. */ - devpriv->ao_stop_continuous = 1; + else /* TRIG_EXT | TRIG_NONE */ devpriv->ao_stop_count = 0; - break; - } - /* - * Sort out start of acquisition. - */ - switch (cmd->start_src) { - case TRIG_INT: - spin_lock_irqsave(&devpriv->ao_spinlock, flags); - s->async->inttrig = &pci224_ao_inttrig_start; - spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - break; - case TRIG_EXT: + spin_lock_irqsave(&devpriv->ao_spinlock, flags); + if (cmd->start_src == TRIG_INT) { + s->async->inttrig = pci224_ao_inttrig_start; + } else { /* TRIG_EXT */ /* Enable external interrupt trigger to start acquisition. */ - spin_lock_irqsave(&devpriv->ao_spinlock, flags); devpriv->intsce |= PCI224_INTR_EXT; outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE); - spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); - break; } + spin_unlock_irqrestore(&devpriv->ao_spinlock, flags); return 0; } @@ -1240,8 +978,10 @@ static void pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index) { - struct comedi_async *async = s->async; - short *array = data; + const struct pci224_board *thisboard = comedi_board(dev); + struct pci224_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned short *array = data; unsigned int length = num_bytes / sizeof(*array); unsigned int offset; unsigned int shift; @@ -1250,7 +990,7 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, /* The hardware expects 16-bit numbers. */ shift = 16 - thisboard->ao_bits; /* Channels will be all bipolar or all unipolar. */ - if ((devpriv->hwrange[CR_RANGE(async->cmd.chanlist[0])] & + if ((devpriv->hwrange[CR_RANGE(cmd->chanlist[0])] & PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) { /* Unipolar */ offset = 0; @@ -1270,7 +1010,8 @@ pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, static irqreturn_t pci224_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = &dev->subdevices[0]; + struct pci224_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->write_subdev; struct comedi_cmd *cmd; unsigned char intstat, valid_intstat; unsigned char curenab; @@ -1315,101 +1056,81 @@ static irqreturn_t pci224_interrupt(int irq, void *d) } /* + * 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 int -pci224_find_pci(struct comedi_device *dev, int bus, int slot, - struct pci_dev **pci_dev_p) +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]; - *pci_dev_p = NULL; - - /* Look for matching PCI device. */ - for (pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, NULL); - pci_dev != NULL; - pci_dev = pci_get_device(PCI_VENDOR_ID_AMPLICON, PCI_ANY_ID, - pci_dev)) { - /* If bus/slot specified, check them. */ + for_each_pci_dev(pci_dev) { if (bus || slot) { - if (bus != pci_dev->bus->number - || slot != PCI_SLOT(pci_dev->devfn)) + 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. */ - int i; + const struct pci224_board *board_ptr; - for (i = 0; i < ARRAY_SIZE(pci224_boards); i++) { - if (pci_dev->device == pci224_boards[i].devid) { - /* Change board_ptr to matched board. */ - dev->board_ptr = &pci224_boards[i]; - break; - } - } - if (i == ARRAY_SIZE(pci224_boards)) + 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; } - - /* Found a match. */ - *pci_dev_p = pci_dev; - return 0; - } - /* No match found. */ - if (bus || slot) { - printk(KERN_ERR "comedi%d: error! " - "no %s found at pci %02x:%02x!\n", - dev->minor, thisboard->name, bus, slot); - } else { - printk(KERN_ERR "comedi%d: error! no %s found!\n", - dev->minor, thisboard->name); + return pci_dev; } - return -EIO; + dev_err(dev->class_dev, + "No supported board found! (req. bus %d, slot %d)\n", + bus, slot); + return NULL; } /* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. + * Common part of attach and auto_attach. */ -static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pci224_attach_common(struct comedi_device *dev, + struct pci_dev *pci_dev, int *options) { + const struct pci224_board *thisboard = comedi_board(dev); + struct pci224_private *devpriv = dev->private; struct comedi_subdevice *s; - struct pci_dev *pci_dev; unsigned int irq; - int bus = 0, slot = 0; unsigned n; int ret; - printk(KERN_DEBUG "comedi%d: %s: attach\n", dev->minor, DRIVER_NAME); + comedi_set_hw_dev(dev, &pci_dev->dev); - bus = it->options[0]; - slot = it->options[1]; - ret = alloc_private(dev, sizeof(struct pci224_private)); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); + ret = comedi_pci_enable(dev); + if (ret) return ret; - } - ret = pci224_find_pci(dev, bus, slot, &pci_dev); - if (ret < 0) - return ret; - - devpriv->pci_dev = pci_dev; - ret = comedi_pci_enable(pci_dev, DRIVER_NAME); - if (ret < 0) { - printk(KERN_ERR - "comedi%d: error! cannot enable PCI device " - "and request regions!\n", dev->minor); - return ret; - } spin_lock_init(&devpriv->ao_spinlock); devpriv->iobase1 = pci_resource_start(pci_dev, 2); @@ -1451,15 +1172,11 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) outw(devpriv->daccon | PCI224_DACCON_FIFORESET, dev->iobase + PCI224_DACCON); - /* Allocate subdevices. There is only one! */ - ret = alloc_subdevices(dev, 1); - if (ret < 0) { - printk(KERN_ERR "comedi%d: error! out of memory!\n", - dev->minor); + ret = comedi_alloc_subdevices(dev, 1); + if (ret) return ret; - } - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* Analog output subdevice. */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; @@ -1486,24 +1203,25 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (!s->range_table_list) return -ENOMEM; - for (n = 2; n < 3 + s->n_chan; n++) { - if (it->options[n] < 0 || it->options[n] > 1) { - printk(KERN_WARNING "comedi%d: %s: warning! " - "bad options[%u]=%d\n", - dev->minor, DRIVER_NAME, n, - it->options[n]); + if (options) { + for (n = 2; n < 3 + s->n_chan; n++) { + if (options[n] < 0 || options[n] > 1) { + dev_warn(dev->class_dev, DRIVER_NAME + ": warning! bad options[%u]=%d\n", + n, options[n]); + } } } for (n = 0; n < s->n_chan; n++) { - if (n < COMEDI_NDEVCONFOPTS - 3 && - it->options[3 + n] == 1) { - if (it->options[2] == 1) + 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 (it->options[2] == 1) { + if (options && options[2] == 1) { range_table_list[n] = &range_pci234_ext2; } else { @@ -1514,14 +1232,14 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->hwrange = hwrange_pci234; } else { /* PCI224 range options. */ - if (it->options[2] == 1) { + if (options && options[2] == 1) { s->range_table = &range_pci224_external; devpriv->hwrange = hwrange_pci224_external; } else { - if (it->options[2] != 0) { - printk(KERN_WARNING "comedi%d: %s: warning! " - "bad options[2]=%d\n", - dev->minor, DRIVER_NAME, it->options[2]); + if (options && options[2] != 0) { + dev_warn(dev->class_dev, DRIVER_NAME + ": warning! bad options[2]=%d\n", + options[2]); } s->range_table = &range_pci224_internal; devpriv->hwrange = hwrange_pci224_internal; @@ -1534,46 +1252,75 @@ static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) ret = request_irq(irq, pci224_interrupt, IRQF_SHARED, DRIVER_NAME, dev); if (ret < 0) { - printk(KERN_ERR "comedi%d: error! " - "unable to allocate irq %u\n", dev->minor, irq); + dev_err(dev->class_dev, + "error! unable to allocate irq %u\n", irq); return ret; } else { dev->irq = irq; } } - printk(KERN_INFO "comedi%d: %s ", dev->minor, dev->board_name); - printk("(pci %s) ", pci_name(pci_dev)); - if (irq) - printk("(irq %u%s) ", irq, (dev->irq ? "" : " UNAVAILABLE")); - else - printk("(no irq) "); + return 0; +} +static int pci224_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct pci224_private *devpriv; + struct pci_dev *pci_dev; - printk("attached\n"); + dev_info(dev->class_dev, DRIVER_NAME ": attach\n"); - return 1; + 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); } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pci224_detach(struct comedi_device *dev) +static int +pci224_auto_attach(struct comedi_device *dev, unsigned long context_unused) { - printk(KERN_DEBUG "comedi%d: %s: detach\n", dev->minor, DRIVER_NAME); + struct pci_dev *pci_dev = comedi_to_pci_dev(dev); + struct pci224_private *devpriv; + + dev_info(dev->class_dev, DRIVER_NAME ": 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, + DRIVER_NAME ": 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; + s = &dev->subdevices[0]; /* AO subdevice */ kfree(s->range_table_list); } @@ -1581,21 +1328,45 @@ static int pci224_detach(struct comedi_device *dev) kfree(devpriv->ao_readback); kfree(devpriv->ao_scan_vals); kfree(devpriv->ao_scan_order); - if (devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - - pci_dev_put(devpriv->pci_dev); - } - } - if (dev->board_name) { - printk(KERN_INFO "comedi%d: %s removed\n", - dev->minor, dev->board_name); } + comedi_pci_disable(dev); + if (pcidev) + pci_dev_put(pcidev); +} - return 0; +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, + .offset = sizeof(struct pci224_board), + .num_names = ARRAY_SIZE(pci224_boards), +}; + +static int amplc_pci224_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &lc_pci224_driver, + id->driver_data); } +static const struct pci_device_id amplc_pci224_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI224) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI234) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table); + +static struct pci_driver amplc_pci224_pci_driver = { + .name = "amplc_pci224", + .id_table = amplc_pci224_pci_table, + .probe = amplc_pci224_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +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_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 7edeb1103dc..3895bc7cb3e 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -16,10 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: amplc_pci230 @@ -188,17 +184,18 @@ Support for PCI230+/260+, more triggered scan functionality, and workarounds for (or detection of) various hardware problems added by Ian Abbott. */ -#include "../comedidev.h" - +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include "comedi_pci.h" +#include "../comedidev.h" + +#include "comedi_fc.h" #include "8253.h" #include "8255.h" /* PCI230 PCI configuration register information */ -#define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_PCI230 0x0000 #define PCI_DEVICE_ID_PCI260 0x0006 #define PCI_DEVICE_ID_INVALID 0xffff @@ -431,9 +428,6 @@ enum { /* Combine old and new bits. */ #define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask))) -/* A generic null function pointer value. */ -#define NULLFUNC 0 - /* Current CPU. XXX should this be hard_smp_processor_id()? */ #define THISCPU smp_processor_id() @@ -500,27 +494,10 @@ static const struct pci230_board pci230_boards[] = { }, }; -static DEFINE_PCI_DEVICE_TABLE(pci230_pci_table) = { - { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, pci230_pci_table); -/* - * Useful for shorthand access to the particular board structure - */ -#define n_pci230_boards ARRAY_SIZE(pci230_boards) -#define thisboard ((const struct pci230_board *)dev->board_ptr) - /* 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 pci230_private { - struct pci_dev *pci_dev; spinlock_t isr_spinlock; /* Interrupt spin lock */ spinlock_t res_spinlock; /* Shared resources spin lock */ spinlock_t ai_stop_spinlock; /* Spin lock for stopping AI command */ @@ -542,14 +519,6 @@ struct pci230_private { * level threshold (PCI230+/260+). */ unsigned short adcg; /* ADCG register value. */ unsigned char int_en; /* Interrupt enables bits. */ - unsigned char ai_continuous; /* Flag set when cmd->stop_src == - * TRIG_NONE - user chooses to stop - * continuous conversion by - * cancelation. */ - unsigned char ao_continuous; /* Flag set when cmd->stop_src == - * TRIG_NONE - user chooses to stop - * continuous conversion by - * cancelation. */ unsigned char ai_bipolar; /* Set if bipolar input range so we * know to mangle it. */ unsigned char ao_bipolar; /* Set if bipolar output range so we @@ -559,8 +528,6 @@ struct pci230_private { unsigned char res_owner[NUM_RESOURCES]; /* Shared resource owners. */ }; -#define devpriv ((struct pci230_private *)dev->private) - /* PCI230 clock source periods in ns */ static const unsigned int pci230_timebase[8] = { [CLK_10MHZ] = TIMEBASE_10MHZ, @@ -571,15 +538,16 @@ static const unsigned int pci230_timebase[8] = { }; /* PCI230 analogue input range table */ -static const struct comedi_lrange pci230_ai_range = { 7, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5) - } +static const struct comedi_lrange pci230_ai_range = { + 7, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5) + } }; /* PCI230 analogue gain bits for each input range. */ @@ -589,117 +557,24 @@ static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 }; static const unsigned char pci230_ai_bipolar[7] = { 1, 1, 1, 1, 0, 0, 0 }; /* PCI230 analogue output range table */ -static const struct comedi_lrange pci230_ao_range = { 2, { - UNI_RANGE(10), - BIP_RANGE(10) - } +static const struct comedi_lrange pci230_ao_range = { + 2, { + UNI_RANGE(10), + BIP_RANGE(10) + } }; /* PCI230 daccon bipolar flag for each analogue output range. */ static const unsigned char pci230_ao_bipolar[2] = { 0, 1 }; -/* - * 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 int pci230_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci230_detach(struct comedi_device *dev); -static struct comedi_driver driver_amplc_pci230 = { - .driver_name = "amplc_pci230", - .module = THIS_MODULE, - .attach = pci230_attach, - .detach = pci230_detach, - .board_name = &pci230_boards[0].name, - .offset = sizeof(pci230_boards[0]), - .num_names = ARRAY_SIZE(pci230_boards), -}; - -static int __devinit driver_amplc_pci230_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_amplc_pci230.driver_name); -} - -static void __devexit driver_amplc_pci230_pci_remove(struct pci_dev *dev) +static unsigned short pci230_ai_read(struct comedi_device *dev) { - comedi_pci_auto_unconfig(dev); -} + const struct pci230_board *thisboard = comedi_board(dev); + struct pci230_private *devpriv = dev->private; + unsigned short data; -static struct pci_driver driver_amplc_pci230_pci_driver = { - .id_table = pci230_pci_table, - .probe = &driver_amplc_pci230_pci_probe, - .remove = __devexit_p(&driver_amplc_pci230_pci_remove) -}; - -static int __init driver_amplc_pci230_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_amplc_pci230); - if (retval < 0) - return retval; - - driver_amplc_pci230_pci_driver.name = - (char *)driver_amplc_pci230.driver_name; - return pci_register_driver(&driver_amplc_pci230_pci_driver); -} - -static void __exit driver_amplc_pci230_cleanup_module(void) -{ - pci_unregister_driver(&driver_amplc_pci230_pci_driver); - comedi_driver_unregister(&driver_amplc_pci230); -} - -module_init(driver_amplc_pci230_init_module); -module_exit(driver_amplc_pci230_cleanup_module); - -static int pci230_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int pci230_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int pci230_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct, - unsigned int mode, uint64_t ns, - unsigned int round); -static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round); -static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct); -static irqreturn_t pci230_interrupt(int irq, void *d); -static int pci230_ao_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int pci230_ao_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void pci230_ao_stop(struct comedi_device *dev, - struct comedi_subdevice *s); -static void pci230_handle_ao_nofifo(struct comedi_device *dev, - struct comedi_subdevice *s); -static int pci230_handle_ao_fifo(struct comedi_device *dev, - struct comedi_subdevice *s); -static int pci230_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int pci230_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void pci230_ai_stop(struct comedi_device *dev, - struct comedi_subdevice *s); -static void pci230_handle_ai(struct comedi_device *dev, - struct comedi_subdevice *s); - -static short pci230_ai_read(struct comedi_device *dev) -{ /* Read sample. */ - short data = (short)inw(dev->iobase + PCI230_ADCDATA); - + data = inw(dev->iobase + 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. */ @@ -714,24 +589,29 @@ static short pci230_ai_read(struct comedi_device *dev) } static inline unsigned short pci230_ao_mangle_datum(struct comedi_device *dev, - short datum) + unsigned short datum) { + const struct pci230_board *thisboard = comedi_board(dev); + 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); - return (unsigned short)datum; + return datum; } static inline void pci230_ao_write_nofifo(struct comedi_device *dev, - short datum, unsigned int chan) + 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; @@ -742,9 +622,11 @@ static inline void pci230_ao_write_nofifo(struct comedi_device *dev, PCI230_DACOUT2)); } -static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum, - unsigned int chan) +static inline 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; @@ -753,293 +635,10 @@ static inline void pci230_ao_write_fifo(struct comedi_device *dev, short datum, dev->iobase + PCI230P2_DACDATA); } -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase1, iobase2; - /* PCI230's I/O spaces 1 and 2 respectively. */ - struct pci_dev *pci_dev = NULL; - int i = 0, irq_hdl, rc; - - printk("comedi%d: amplc_pci230: attach %s %d,%d\n", dev->minor, - thisboard->name, it->options[0], it->options[1]); - - /* Allocate the private structure area using alloc_private(). - * Macro defined in comedidev.h - memsets struct fields to 0. */ - if ((alloc_private(dev, sizeof(struct pci230_private))) < 0) - return -ENOMEM; - - spin_lock_init(&devpriv->isr_spinlock); - spin_lock_init(&devpriv->res_spinlock); - spin_lock_init(&devpriv->ai_stop_spinlock); - spin_lock_init(&devpriv->ao_stop_spinlock); - /* Find card */ - for_each_pci_dev(pci_dev) { - if (it->options[0] || it->options[1]) { - /* Match against bus/slot options. */ - if (it->options[0] != pci_dev->bus->number || - it->options[1] != PCI_SLOT(pci_dev->devfn)) - continue; - } - if (pci_dev->vendor != PCI_VENDOR_ID_AMPLICON) - continue; - if (thisboard->id == PCI_DEVICE_ID_INVALID) { - /* The name was specified as "amplc_pci230" which is - * used to match any supported device. Replace the - * current dev->board_ptr with one that matches the - * PCI device ID. */ - for (i = 0; i < n_pci230_boards; i++) { - if (pci_dev->device == pci230_boards[i].id) { - if (pci230_boards[i].min_hwver > 0) { - /* Check for a '+' model. - * First check length of - * registers. */ - if (pci_resource_len(pci_dev, 3) - < 32) { - /* Not a '+' model. */ - continue; - } - /* TODO: temporarily enable the - * PCI device and read the - * hardware version register. - * For now assume it's okay. */ - } - /* Change board_ptr to matched board */ - dev->board_ptr = &pci230_boards[i]; - break; - } - } - if (i < n_pci230_boards) - break; - } else { - /* The name was specified as a specific device name. - * The current dev->board_ptr is correct. Check - * whether it matches the PCI device ID. */ - if (thisboard->id == pci_dev->device) { - /* Check minimum hardware version. */ - if (thisboard->min_hwver > 0) { - /* Looking for a '+' model. First - * check length of registers. */ - if (pci_resource_len(pci_dev, 3) < 32) { - /* Not a '+' model. */ - continue; - } - /* TODO: temporarily enable the PCI - * device and read the hardware version - * register. For now, assume it's - * okay. */ - break; - } else { - break; - } - } - } - } - if (!pci_dev) { - printk("comedi%d: No %s card found\n", dev->minor, - thisboard->name); - return -EIO; - } - devpriv->pci_dev = pci_dev; - - /* - * Initialize dev->board_name. - */ - dev->board_name = thisboard->name; - - /* Enable PCI device and reserve I/O spaces. */ - if (comedi_pci_enable(pci_dev, "amplc_pci230") < 0) { - printk("comedi%d: failed to enable PCI device " - "and request regions\n", dev->minor); - return -EIO; - } - - /* 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); - - printk("comedi%d: %s I/O region 1 0x%04lx I/O region 2 0x%04lx\n", - dev->minor, dev->board_name, iobase1, iobase2); - - devpriv->iobase1 = iobase1; - dev->iobase = iobase2; - - /* Read bits of DACCON register - only the output range. */ - devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK; - - /* Read hardware version register and set extended function register - * if they exist. */ - if (pci_resource_len(pci_dev, 3) >= 32) { - unsigned short extfunc = 0; - - devpriv->hwver = inw(dev->iobase + PCI230P_HWVER); - if (devpriv->hwver < thisboard->min_hwver) { - printk("comedi%d: %s - bad hardware version " - "- got %u, need %u\n", dev->minor, - dev->board_name, devpriv->hwver, - thisboard->min_hwver); - return -EIO; - } - if (devpriv->hwver > 0) { - if (!thisboard->have_dio) { - /* No DIO ports. Route counters' external gates - * to the EXTTRIG signal (PCI260+ pin 17). - * (Otherwise, they would be routed to DIO - * inputs PC0, PC1 and PC2 which don't exist - * on PCI260[+].) */ - extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG; - } - if ((thisboard->ao_chans > 0) - && (devpriv->hwver >= 2)) { - /* Enable DAC FIFO functionality. */ - extfunc |= PCI230P2_EXTFUNC_DACFIFO; - } - } - outw(extfunc, dev->iobase + PCI230P_EXTFUNC); - if ((extfunc & PCI230P2_EXTFUNC_DACFIFO) != 0) { - /* Temporarily enable DAC FIFO, reset it and disable - * FIFO wraparound. */ - outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN - | PCI230P2_DAC_FIFO_RESET, - dev->iobase + PCI230_DACCON); - /* Clear DAC FIFO channel enable register. */ - outw(0, dev->iobase + PCI230P2_DACEN); - /* Disable DAC FIFO. */ - outw(devpriv->daccon, dev->iobase + PCI230_DACCON); - } - } - - /* Disable board's interrupts. */ - outb(0, devpriv->iobase1 + 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(devpriv->adccon | PCI230_ADC_FIFO_RESET, - dev->iobase + PCI230_ADCCON); - - /* Register the interrupt handler. */ - irq_hdl = request_irq(devpriv->pci_dev->irq, pci230_interrupt, - IRQF_SHARED, "amplc_pci230", dev); - if (irq_hdl < 0) { - printk("comedi%d: unable to register irq, " - "commands will not be available %d\n", dev->minor, - devpriv->pci_dev->irq); - } else { - dev->irq = devpriv->pci_dev->irq; - printk("comedi%d: registered irq %u\n", dev->minor, - devpriv->pci_dev->irq); - } - - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND; - s->n_chan = thisboard->ai_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = &pci230_ai_range; - s->insn_read = &pci230_ai_rinsn; - s->len_chanlist = 256; /* but there are restrictions. */ - /* Only register commands if the interrupt handler is installed. */ - if (irq_hdl == 0) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmd = &pci230_ai_cmd; - s->do_cmdtest = &pci230_ai_cmdtest; - s->cancel = pci230_ai_cancel; - } - - s = dev->subdevices + 1; - /* analog output subdevice */ - if (thisboard->ao_chans > 0) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = thisboard->ao_chans; - 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; - /* Only register commands if the interrupt handler is - * installed. */ - if (irq_hdl == 0) { - dev->write_subdev = s; - s->subdev_flags |= SDF_CMD_WRITE; - s->do_cmd = &pci230_ao_cmd; - s->do_cmdtest = &pci230_ao_cmdtest; - s->cancel = pci230_ao_cancel; - } - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - s = dev->subdevices + 2; - /* digital i/o subdevice */ - if (thisboard->have_dio) { - rc = subdev_8255_init(dev, s, NULL, - (devpriv->iobase1 + PCI230_PPI_X_BASE)); - if (rc < 0) - return rc; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - printk("comedi%d: attached\n", dev->minor); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pci230_detach(struct comedi_device *dev) -{ - printk("comedi%d: amplc_pci230: remove\n", dev->minor); - - if (dev->subdevices && thisboard->have_dio) - /* Clean up dio subdevice. */ - subdev_8255_cleanup(dev, dev->subdevices + 2); - - if (dev->irq) - free_irq(dev->irq, dev); - - if (devpriv) { - if (devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - - pci_dev_put(devpriv->pci_dev); - } - } - - return 0; -} - static int get_resources(struct comedi_device *dev, unsigned int res_mask, unsigned char owner) { + struct pci230_private *devpriv = dev->private; int ok; unsigned int i; unsigned int b; @@ -1082,6 +681,7 @@ static inline int get_one_resource(struct comedi_device *dev, static void put_resources(struct comedi_device *dev, unsigned int res_mask, unsigned char owner) { + struct pci230_private *devpriv = dev->private; unsigned int i; unsigned int b; unsigned long irqflags; @@ -1111,18 +711,109 @@ static inline void put_all_resources(struct comedi_device *dev, put_resources(dev, (1U << NUM_RESOURCES) - 1, owner); } -/* - * COMEDI_SUBD_AI instruction; - */ +static unsigned int divide_ns(uint64_t ns, unsigned int timebase, + unsigned int round_mode) +{ + uint64_t div; + unsigned int rem; + + div = ns; + rem = do_div(div, timebase); + round_mode &= TRIG_ROUND_MASK; + switch (round_mode) { + default: + case TRIG_ROUND_NEAREST: + div += (rem + (timebase / 2)) / timebase; + break; + case TRIG_ROUND_DOWN: + break; + case TRIG_ROUND_UP: + div += (rem + timebase - 1) / timebase; + break; + } + return div > UINT_MAX ? UINT_MAX : (unsigned int)div; +} + +/* Given desired period in ns, returns the required internal clock source + * and gets the initial count. */ +static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count, + unsigned int round_mode) +{ + unsigned int clk_src, cnt; + + for (clk_src = CLK_10MHZ;; clk_src++) { + cnt = divide_ns(ns, pci230_timebase[clk_src], round_mode); + if ((cnt <= 65536) || (clk_src == CLK_1KHZ)) + break; + + } + *count = cnt; + return clk_src; +} + +static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round) +{ + unsigned int count; + unsigned int clk_src; + + clk_src = pci230_choose_clk_count(*ns, &count, round); + *ns = count * pci230_timebase[clk_src]; + return; +} + +static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct, + unsigned int mode, uint64_t ns, + unsigned int round) +{ + 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); + /* Determine clock source and count. */ + clk_src = pci230_choose_clk_count(ns, &count, round); + /* Program clock source. */ + outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE); + /* Set initial count. */ + if (count >= 65536) + count = 0; + + i8254_write(devpriv->iobase1 + 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); + /* Counter ct, 8254 mode 1, initial count not written. */ +} + +static int pci230_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + PCI230_ADCCON); + if ((status & PCI230_ADC_FIFO_EMPTY) == 0) + return 0; + return -EBUSY; +} + static int pci230_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - unsigned int n, i; + struct pci230_private *devpriv = dev->private; + unsigned int n; unsigned int chan, range, aref; unsigned int gainshift; - unsigned int status; unsigned short adccon, adcen; + int ret; /* Unpack channel and range. */ chan = CR_CHAN(insn->chanspec); @@ -1131,9 +822,9 @@ static int pci230_ai_rinsn(struct comedi_device *dev, if (aref == AREF_DIFF) { /* Differential. */ if (chan >= s->n_chan / 2) { - DPRINTK("comedi%d: amplc_pci230: ai_rinsn: " - "differential channel number out of range " - "0 to %u\n", dev->minor, (s->n_chan / 2) - 1); + dev_dbg(dev->class_dev, + "%s: differential channel number out of range 0 to %u\n", + __func__, (s->n_chan / 2) - 1); return -EINVAL; } } @@ -1194,20 +885,10 @@ static int pci230_ai_rinsn(struct comedi_device *dev, i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, 2, I8254_MODE1); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(dev->iobase + PCI230_ADCCON); - if (!(status & PCI230_ADC_FIFO_EMPTY)) - break; - udelay(1); - } - if (i == TIMEOUT) { - /* printk() should be used instead of printk() - * whenever the code can be called from real-time. */ - printk("timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, pci230_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = pci230_ai_read(dev); @@ -1224,6 +905,7 @@ static int pci230_ao_winsn(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, range; @@ -1253,6 +935,7 @@ 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); @@ -1262,29 +945,51 @@ static int pci230_ao_rinsn(struct comedi_device *dev, return i; } +static int pci230_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int prev_chan = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan < prev_chan) { + dev_dbg(dev->class_dev, + "%s: channel numbers must increase\n", + __func__); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "%s: channels must have the same range\n", + __func__); + return -EINVAL; + } + + prev_chan = chan; + } + + return 0; +} + static int pci230_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct pci230_board *thisboard = comedi_board(dev); + struct pci230_private *devpriv = dev->private; int err = 0; unsigned int tmp; - /* 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. */ + /* Step 1 : check if triggers are trivially valid */ - /* Step 1: make sure trigger sources are trivially valid. - * "invalid source" returned by comedilib to user mode process - * if this fails. */ + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; + tmp = TRIG_TIMER | TRIG_INT; if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) { /* * For PCI230+ hardware version 2 onwards, allow external @@ -1300,58 +1005,31 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, * scan_begin_src==TRIG_EXT support to be a bonus rather than a * guarantee! */ - cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT; - } else { - cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT; + tmp |= TRIG_EXT; } - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, tmp); - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* Step 2: make sure trigger sources are unique and mutually compatible - * "source conflict" returned by comedilib to user mode process - * if this fails. */ + /* Step 2a : make sure trigger sources are unique */ - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* Step 3: make sure arguments are trivially compatible. - * "invalid argument" returned by comedilib to user mode process - * if this fails. */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } #define MAX_SPEED_AO 8000 /* 8000 ns => 125 kHz */ #define MIN_SPEED_AO 4294967295u /* 4294967295ns = 4.29s */ /*- Comedi limit due to unsigned int cmd. Driver limit @@ -1360,14 +1038,10 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, switch (cmd->scan_begin_src) { case TRIG_TIMER: - if (cmd->scan_begin_arg < MAX_SPEED_AO) { - cmd->scan_begin_arg = MAX_SPEED_AO; - err++; - } - if (cmd->scan_begin_arg > MIN_SPEED_AO) { - cmd->scan_begin_arg = MIN_SPEED_AO; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + MAX_SPEED_AO); + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, + MIN_SPEED_AO); break; case TRIG_EXT: /* External trigger - for PCI230+ hardware version 2 onwards. */ @@ -1375,37 +1049,27 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) { cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK); - err++; + err |= -EINVAL; } /* 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))) != 0) { - cmd->scan_begin_arg = - COMBINE(cmd->scan_begin_arg, 0, - CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT)); - err++; + cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, + CR_FLAGS_MASK & + ~(CR_EDGE | CR_INVERT)); + err |= -EINVAL; } break; default: - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); break; } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_NONE) { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_NONE) + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; @@ -1425,48 +1089,9 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, if (err) return 4; - /* Step 5: check channel list if it exists. */ - - if (cmd->chanlist && cmd->chanlist_len > 0) { - enum { - seq_err = (1 << 0), - range_err = (1 << 1) - }; - unsigned int errors; - unsigned int n; - unsigned int chan, prev_chan; - unsigned int range, first_range; - - prev_chan = CR_CHAN(cmd->chanlist[0]); - first_range = CR_RANGE(cmd->chanlist[0]); - errors = 0; - for (n = 1; n < cmd->chanlist_len; n++) { - chan = CR_CHAN(cmd->chanlist[n]); - range = CR_RANGE(cmd->chanlist[n]); - /* Channel numbers must strictly increase. */ - if (chan < prev_chan) - errors |= seq_err; - - /* Ranges must be the same. */ - if (range != first_range) - errors |= range_err; - - prev_chan = chan; - } - if (errors != 0) { - err++; - if ((errors & seq_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: " - "channel numbers must increase\n", - dev->minor); - } - if ((errors & range_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ao_cmdtest: " - "channels must have the same range\n", - dev->minor); - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci230_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1474,10 +1099,199 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, return 0; } +static void pci230_ao_stop(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci230_private *devpriv = dev->private; + unsigned long irqflags; + unsigned char intsrc; + int started; + struct comedi_cmd *cmd; + + spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); + started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state); + spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); + if (!started) + return; + cmd = &s->async->cmd; + if (cmd->scan_begin_src == TRIG_TIMER) { + /* Stop scan rate generator. */ + pci230_cancel_ct(dev, 1); + } + /* Determine interrupt source. */ + if (devpriv->hwver < 2) { + /* Not using DAC FIFO. Using CT1 interrupt. */ + intsrc = PCI230_INT_ZCLK_CT1; + } else { + /* Using DAC FIFO interrupt. */ + intsrc = PCI230P2_INT_DAC; + } + /* Disable interrupt and wait for interrupt routine to finish running + * unless we are called from the interrupt routine. */ + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + devpriv->int_en &= ~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); + } + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + if (devpriv->hwver >= 2) { + /* Using DAC FIFO. Reset FIFO, clear underrun error, + * disable FIFO. */ + devpriv->daccon &= PCI230_DAC_OR_MASK; + outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET + | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR, + dev->iobase + PCI230_DACCON); + } + /* Release resources. */ + put_all_resources(dev, OWNER_AOCMD); +} + +static void pci230_handle_ao_nofifo(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci230_private *devpriv = dev->private; + unsigned short data; + int i, ret; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) + return; + for (i = 0; i < cmd->chanlist_len; i++) { + /* Read sample from Comedi's circular buffer. */ + ret = comedi_buf_get(s, &data); + if (ret == 0) { + s->async->events |= COMEDI_CB_OVERFLOW; + pci230_ao_stop(dev, s); + comedi_error(dev, "AO buffer underrun"); + return; + } + /* Write value to DAC. */ + pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i])); + } + async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + if (cmd->stop_src == TRIG_COUNT) { + devpriv->ao_scan_count--; + if (devpriv->ao_scan_count == 0) { + /* End of acquisition. */ + async->events |= COMEDI_CB_EOA; + pci230_ao_stop(dev, s); + } + } +} + +/* 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) +{ + struct pci230_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int num_scans; + unsigned int room; + unsigned short dacstat; + unsigned int i, n; + unsigned int events = 0; + int running; + + /* Get DAC FIFO status. */ + dacstat = inw(dev->iobase + 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) { + /* Fixed number of scans. */ + if (num_scans > devpriv->ao_scan_count) + num_scans = devpriv->ao_scan_count; + if (devpriv->ao_scan_count == 0) { + /* End of acquisition. */ + events |= COMEDI_CB_EOA; + } + } + if (events == 0) { + /* Check for FIFO underrun. */ + if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) { + comedi_error(dev, "AO FIFO underrun"); + events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + } + /* Check for buffer underrun if FIFO less than half full + * (otherwise there will be loads of "DAC FIFO not half full" + * interrupts). */ + if ((num_scans == 0) + && ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) { + comedi_error(dev, "AO buffer underrun"); + events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + } + } + if (events == 0) { + /* Determine how much room is in the FIFO (in samples). */ + if ((dacstat & PCI230P2_DAC_FIFO_FULL) != 0) + room = PCI230P2_DAC_FIFOROOM_FULL; + else if ((dacstat & PCI230P2_DAC_FIFO_HALF) != 0) + room = PCI230P2_DAC_FIFOROOM_HALFTOFULL; + else if ((dacstat & PCI230P2_DAC_FIFO_EMPTY) != 0) + room = PCI230P2_DAC_FIFOROOM_EMPTY; + else + room = PCI230P2_DAC_FIFOROOM_ONETOHALF; + /* Convert room to number of scans that can be added. */ + room /= cmd->chanlist_len; + /* Determine number of scans to process. */ + if (num_scans > room) + num_scans = room; + /* Process scans. */ + for (n = 0; n < num_scans; n++) { + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned short datum; + + comedi_buf_get(s, &datum); + pci230_ao_write_fifo(dev, datum, + CR_CHAN(cmd->chanlist[i])); + } + } + events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK; + if (cmd->stop_src == TRIG_COUNT) { + devpriv->ao_scan_count -= num_scans; + if (devpriv->ao_scan_count == 0) { + /* All data for the command has been written + * to FIFO. Set FIFO interrupt trigger level + * to 'empty'. */ + devpriv->daccon = (devpriv->daccon + & + ~PCI230P2_DAC_INT_FIFO_MASK) + | PCI230P2_DAC_INT_FIFO_EMPTY; + outw(devpriv->daccon, + dev->iobase + PCI230_DACCON); + } + } + /* Check if FIFO underrun occurred while writing to FIFO. */ + dacstat = inw(dev->iobase + PCI230_DACCON); + if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) { + comedi_error(dev, "AO FIFO underrun"); + events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + } + } + if ((events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) + != 0) { + /* Stopping AO due to completion or error. */ + pci230_ao_stop(dev, s); + running = 0; + } else { + running = 1; + } + async->events |= events; + return running; +} + static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { + struct pci230_private *devpriv = dev->private; unsigned long irqflags; if (trig_num != 0) @@ -1502,6 +1316,8 @@ static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev, /* Delay. Should driver be responsible for this? */ /* XXX TODO: See if DAC busy bit can be used. */ udelay(8); + } else { + spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); } return 1; @@ -1510,12 +1326,13 @@ static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev, static void pci230_ao_start(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci230_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned long irqflags; set_bit(AO_CMD_STARTED, &devpriv->state); - if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_scan_count == 0) { /* An empty acquisition! */ async->events |= COMEDI_CB_EOA; pci230_ao_stop(dev, s); @@ -1600,10 +1417,12 @@ static int pci230_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { - if (trig_num != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_src) return -EINVAL; - s->async->inttrig = NULLFUNC; + s->async->inttrig = NULL; pci230_ao_start(dev, s); return 1; @@ -1611,6 +1430,7 @@ static int pci230_ao_inttrig_start(struct comedi_device *dev, static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci230_private *devpriv = dev->private; unsigned short daccon; unsigned int range; @@ -1625,14 +1445,10 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) devpriv->ao_scan_count = cmd->stop_arg; - devpriv->ao_continuous = 0; - } else { - /* TRIG_NONE, user calls cancel. */ + else /* TRIG_NONE, user calls cancel */ devpriv->ao_scan_count = 0; - devpriv->ao_continuous = 1; - } /* Set range - see analogue output range table; 0 => unipolar 10V, * 1 => bipolar +/-10V range scale */ @@ -1686,6 +1502,13 @@ static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } +static int pci230_ao_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + pci230_ao_stop(dev, s); + return 0; +} + static int pci230_ai_check_scan_period(struct comedi_cmd *cmd) { unsigned int min_scan_period, chanlist_len; @@ -1710,93 +1533,164 @@ static int pci230_ai_check_scan_period(struct comedi_cmd *cmd) return !err; } +static int pci230_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + struct pci230_private *devpriv = dev->private; + unsigned int max_diff_chan = (s->n_chan / 2) - 1; + unsigned int prev_chan = 0; + unsigned int prev_range = 0; + unsigned int prev_aref = 0; + unsigned int prev_polarity = 0; + unsigned int subseq_len = 0; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chanspec = cmd->chanlist[i]; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int polarity = pci230_ai_bipolar[range]; + + if (aref == AREF_DIFF && chan >= max_diff_chan) { + dev_dbg(dev->class_dev, + "%s: differential channel number out of range 0 to %u\n", + __func__, max_diff_chan); + return -EINVAL; + } + + if (i > 0) { + /* + * Channel numbers must strictly increase or + * subsequence must repeat exactly. + */ + if (chan <= prev_chan && subseq_len == 0) + subseq_len = i; + + if (subseq_len > 0 && + cmd->chanlist[i % subseq_len] != chanspec) { + dev_dbg(dev->class_dev, + "%s: channel numbers must increase or sequence must repeat exactly\n", + __func__); + return -EINVAL; + } + + if (aref != prev_aref) { + dev_dbg(dev->class_dev, + "%s: channel sequence analogue references must be all the same (single-ended or differential)\n", + __func__); + return -EINVAL; + } + + if (polarity != prev_polarity) { + dev_dbg(dev->class_dev, + "%s: channel sequence ranges must be all bipolar or all unipolar\n", + __func__); + return -EINVAL; + } + + if (aref != AREF_DIFF && range != prev_range && + ((chan ^ prev_chan) & ~1) == 0) { + dev_dbg(dev->class_dev, + "%s: single-ended channel pairs must have the same range\n", + __func__); + return -EINVAL; + } + } + prev_chan = chan; + prev_range = range; + prev_aref = aref; + prev_polarity = polarity; + } + + if (subseq_len == 0) + subseq_len = cmd->chanlist_len; + + if ((cmd->chanlist_len % subseq_len) != 0) { + dev_dbg(dev->class_dev, + "%s: sequence must repeat exactly\n", __func__); + return -EINVAL; + } + + /* + * Buggy PCI230+ or PCI260+ requires channel 0 to be (first) in the + * sequence if the sequence contains more than one channel. Hardware + * versions 1 and 2 have the bug. There is no hardware version 3. + * + * Actually, there are two firmwares that report themselves as + * hardware version 1 (the boards have different ADC chips with + * slightly different timing requirements, which was supposed to + * be invisible to software). The first one doesn't seem to have + * the bug, but the second one does, and we can't tell them apart! + */ + if (devpriv->hwver > 0 && devpriv->hwver < 4) { + if (subseq_len > 1 && CR_CHAN(cmd->chanlist[0]) != 0) { + dev_info(dev->class_dev, + "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n", + devpriv->hwver); + return -EINVAL; + } + } + + return 0; +} + static int pci230_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct pci230_board *thisboard = comedi_board(dev); + struct pci230_private *devpriv = dev->private; int err = 0; unsigned int tmp; - /* 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,5 or 0, depending on which tests - * the command passes. */ - - /* Step 1: make sure trigger sources are trivially valid. - * "invalid source" returned by comedilib to user mode process - * if this fails. */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - tmp = cmd->scan_begin_src; - /* Unfortunately, we cannot trigger a scan off an external source - * on the PCI260 board, since it uses the PPIC0 (DIO) input, which - * isn't present on the PCI260. For PCI260+ we can use the - * EXTTRIG/EXTCONVCLK input on pin 17 instead. */ + tmp = TRIG_FOLLOW | TRIG_TIMER | TRIG_INT; if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) { - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT - | TRIG_EXT; - } else { - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT; + /* + * Unfortunately, we cannot trigger a scan off an external + * source on the PCI260 board, since it uses the PPIC0 (DIO) + * input, which isn't present on the PCI260. For PCI260+ + * we can use the EXTTRIG/EXTCONVCLK input on pin 17 instead. + */ + tmp |= TRIG_EXT; } - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, tmp); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_INT | 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 2: make sure trigger sources are unique and mutually compatible - * "source conflict" returned by comedilib to user mode process - * if this fails. */ + /* Step 2a : make sure trigger sources are unique */ - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; + 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 scan_begin_src is not TRIG_FOLLOW, then a monostable will be - * set up to generate a fixed number of timed conversion pulses. */ + /* + * 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)) - err++; + err |= -EINVAL; if (err) return 2; - /* Step 3: make sure arguments are trivially compatible. - * "invalid argument" returned by comedilib to user mode process - * if this fails. */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } #define MAX_SPEED_AI_SE 3200 /* PCI230 SE: 3200 ns => 312.5 kHz */ #define MAX_SPEED_AI_DIFF 8000 /* PCI230 DIFF: 8000 ns => 125 kHz */ #define MAX_SPEED_AI_PLUS 4000 /* PCI230+: 4000 ns => 250 kHz */ @@ -1827,14 +1721,10 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, max_speed_ai = MAX_SPEED_AI_PLUS; } - if (cmd->convert_arg < max_speed_ai) { - cmd->convert_arg = max_speed_ai; - err++; - } - if (cmd->convert_arg > MIN_SPEED_AI) { - cmd->convert_arg = MIN_SPEED_AI; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + max_speed_ai); + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, + MIN_SPEED_AI); } else if (cmd->convert_src == TRIG_EXT) { /* * external trigger @@ -1849,46 +1739,33 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, if ((cmd->convert_arg & ~CR_FLAGS_MASK) != 0) { cmd->convert_arg = COMBINE(cmd->convert_arg, 0, ~CR_FLAGS_MASK); - err++; + err |= -EINVAL; } /* 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) { /* Set CR_EDGE, preserve CR_INVERT. */ - cmd->convert_arg = - COMBINE(cmd->start_arg, (CR_EDGE | 0), - CR_FLAGS_MASK & ~CR_INVERT); - err++; + cmd->convert_arg = COMBINE(cmd->start_arg, + (CR_EDGE | 0), + CR_FLAGS_MASK & + ~CR_INVERT); + err |= -EINVAL; } } else { /* Backwards compatibility with previous versions. */ /* convert_arg == 0 => trigger on -ve edge. */ /* convert_arg == 1 => trigger on +ve edge. */ - if (cmd->convert_arg > 1) { - /* Default to trigger on +ve edge. */ - cmd->convert_arg = 1; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 1); } } else { - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->stop_src == TRIG_NONE) { - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + if (cmd->stop_src == TRIG_NONE) + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (cmd->scan_begin_src == TRIG_EXT) { /* external "trigger" to begin each scan @@ -1897,24 +1774,21 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, if ((cmd->scan_begin_arg & ~CR_FLAGS_MASK) != 0) { cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK); - err++; + err |= -EINVAL; } /* The only flag allowed is CR_EDGE, which is ignored. */ if ((cmd->scan_begin_arg & CR_FLAGS_MASK & ~CR_EDGE) != 0) { cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0, CR_FLAGS_MASK & ~CR_EDGE); - err++; + err |= -EINVAL; } } else if (cmd->scan_begin_src == TRIG_TIMER) { /* N.B. cmd->convert_arg is also TRIG_TIMER */ if (!pci230_ai_check_scan_period(cmd)) - err++; + err |= -EINVAL; } else { - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); } if (err) @@ -1950,144 +1824,9 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, if (err) return 4; - /* Step 5: check channel list if it exists. */ - - if (cmd->chanlist && cmd->chanlist_len > 0) { - enum { - seq_err = 1 << 0, - rangepair_err = 1 << 1, - polarity_err = 1 << 2, - aref_err = 1 << 3, - diffchan_err = 1 << 4, - buggy_chan0_err = 1 << 5 - }; - unsigned int errors; - unsigned int chan, prev_chan; - unsigned int range, prev_range; - unsigned int polarity, prev_polarity; - unsigned int aref, prev_aref; - unsigned int subseq_len; - unsigned int n; - - subseq_len = 0; - errors = 0; - prev_chan = prev_aref = prev_range = prev_polarity = 0; - for (n = 0; n < cmd->chanlist_len; n++) { - chan = CR_CHAN(cmd->chanlist[n]); - range = CR_RANGE(cmd->chanlist[n]); - aref = CR_AREF(cmd->chanlist[n]); - polarity = pci230_ai_bipolar[range]; - /* Only the first half of the channels are available if - * differential. (These are remapped in software. In - * hardware, only the even channels are available.) */ - if ((aref == AREF_DIFF) - && (chan >= (s->n_chan / 2))) { - errors |= diffchan_err; - } - if (n > 0) { - /* Channel numbers must strictly increase or - * subsequence must repeat exactly. */ - if ((chan <= prev_chan) - && (subseq_len == 0)) { - subseq_len = n; - } - if ((subseq_len > 0) - && (cmd->chanlist[n] != - cmd->chanlist[n % subseq_len])) { - errors |= seq_err; - } - /* Channels must have same AREF. */ - if (aref != prev_aref) - errors |= aref_err; - - /* Channel ranges must have same polarity. */ - if (polarity != prev_polarity) - errors |= polarity_err; - - /* Single-ended channel pairs must have same - * range. */ - if ((aref != AREF_DIFF) - && (((chan ^ prev_chan) & ~1) == 0) - && (range != prev_range)) { - errors |= rangepair_err; - } - } - prev_chan = chan; - prev_range = range; - prev_aref = aref; - prev_polarity = polarity; - } - if (subseq_len == 0) { - /* Subsequence is whole sequence. */ - subseq_len = n; - } - /* If channel list is a repeating subsequence, need a whole - * number of repeats. */ - if ((n % subseq_len) != 0) - errors |= seq_err; - - if ((devpriv->hwver > 0) && (devpriv->hwver < 4)) { - /* - * Buggy PCI230+ or PCI260+ requires channel 0 to be - * (first) in the sequence if the sequence contains - * more than one channel. Hardware versions 1 and 2 - * have the bug. There is no hardware version 3. - * - * Actually, there are two firmwares that report - * themselves as hardware version 1 (the boards - * have different ADC chips with slightly different - * timing requirements, which was supposed to be - * invisible to software). The first one doesn't - * seem to have the bug, but the second one - * does, and we can't tell them apart! - */ - if ((subseq_len > 1) - && (CR_CHAN(cmd->chanlist[0]) != 0)) { - errors |= buggy_chan0_err; - } - } - if (errors != 0) { - err++; - if ((errors & seq_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "channel numbers must increase or " - "sequence must repeat exactly\n", - dev->minor); - } - if ((errors & rangepair_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "single-ended channel pairs must " - "have the same range\n", dev->minor); - } - if ((errors & polarity_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "channel sequence ranges must be all " - "bipolar or all unipolar\n", - dev->minor); - } - if ((errors & aref_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "channel sequence analogue references " - "must be all the same (single-ended " - "or differential)\n", dev->minor); - } - if ((errors & diffchan_err) != 0) { - DPRINTK("comedi%d: amplc_pci230: ai_cmdtest: " - "differential channel number out of " - "range 0 to %u\n", dev->minor, - (s->n_chan / 2) - 1); - } - if ((errors & buggy_chan0_err) != 0) { - /* Use printk instead of DPRINTK here. */ - printk("comedi: comedi%d: amplc_pci230: " - "ai_cmdtest: Buggy PCI230+/260+ " - "h/w version %u requires first channel " - "of multi-channel sequence to be 0 " - "(corrected in h/w version 4)\n", - dev->minor, devpriv->hwver); - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= pci230_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -2098,6 +1837,7 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci230_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int scanlen = cmd->scan_end_arg; unsigned int wake; @@ -2108,9 +1848,9 @@ static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev, /* Wake at end of scan. */ wake = scanlen - devpriv->ai_scan_pos; } else { - if (devpriv->ai_continuous - || (devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL) - || (scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL)) { + if (cmd->stop_src != TRIG_COUNT || + devpriv->ai_scan_count >= PCI230_ADC_FIFOLEVEL_HALFFULL || + scanlen >= PCI230_ADC_FIFOLEVEL_HALFFULL) { wake = PCI230_ADC_FIFOLEVEL_HALFFULL; } else { wake = (devpriv->ai_scan_count * scanlen) @@ -2142,6 +1882,7 @@ static int pci230_ai_inttrig_convert(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { + struct pci230_private *devpriv = dev->private; unsigned long irqflags; if (trig_num != 0) @@ -2184,6 +1925,7 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { + struct pci230_private *devpriv = dev->private; unsigned long irqflags; unsigned char zgat; @@ -2203,16 +1945,63 @@ static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev, return 1; } +static void pci230_ai_stop(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci230_private *devpriv = dev->private; + unsigned long irqflags; + struct comedi_cmd *cmd; + int started; + + spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); + started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state); + spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); + if (!started) + return; + cmd = &s->async->cmd; + if (cmd->convert_src == TRIG_TIMER) { + /* Stop conversion rate generator. */ + pci230_cancel_ct(dev, 2); + } + if (cmd->scan_begin_src != TRIG_FOLLOW) { + /* Stop scan period monostable. */ + pci230_cancel_ct(dev, 0); + } + spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); + /* 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; + 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); + } + spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + /* Reset FIFO, disable FIFO and set start conversion source to none. + * Keep se/diff and bip/uni settings */ + devpriv->adccon = (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); + /* Release resources. */ + put_all_resources(dev, OWNER_AICMD); +} + static void pci230_ai_start(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci230_private *devpriv = dev->private; unsigned long irqflags; unsigned short conv; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; set_bit(AI_CMD_STARTED, &devpriv->state); - if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) { + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { /* An empty acquisition! */ async->events |= COMEDI_CB_EOA; pci230_ai_stop(dev, s); @@ -2345,17 +2134,114 @@ static int pci230_ai_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { - if (trig_num != 0) + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; - s->async->inttrig = NULLFUNC; + s->async->inttrig = NULL; pci230_ai_start(dev, s); return 1; } +static void pci230_handle_ai(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci230_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int scanlen = cmd->scan_end_arg; + unsigned int events = 0; + unsigned int status_fifo; + unsigned int i; + unsigned int todo; + unsigned int fifoamount; + + /* Determine number of samples to read. */ + if (cmd->stop_src != TRIG_COUNT) { + 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)) { + todo = PCI230_ADC_FIFOLEVEL_HALFFULL; + } else { + todo = (devpriv->ai_scan_count * scanlen) + - devpriv->ai_scan_pos; + if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL) + todo = PCI230_ADC_FIFOLEVEL_HALFFULL; + } + if (todo == 0) + return; + fifoamount = 0; + for (i = 0; i < todo; i++) { + if (fifoamount == 0) { + /* Read FIFO state. */ + status_fifo = inw(dev->iobase + PCI230_ADCCON); + if ((status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) != 0) { + /* Report error otherwise FIFO overruns will go + * unnoticed by the caller. */ + comedi_error(dev, "AI FIFO overrun"); + events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + break; + } else if ((status_fifo & PCI230_ADC_FIFO_EMPTY) != 0) { + /* FIFO empty. */ + break; + } else if ((status_fifo & PCI230_ADC_FIFO_HALF) != 0) { + /* FIFO half full. */ + fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL; + } 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; + } + } + } + /* Read sample and store in Comedi's circular buffer. */ + if (comedi_buf_put(s, pci230_ai_read(dev)) == 0) { + events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; + comedi_error(dev, "AI buffer overflow"); + break; + } + fifoamount--; + devpriv->ai_scan_pos++; + if (devpriv->ai_scan_pos == scanlen) { + /* End of scan. */ + devpriv->ai_scan_pos = 0; + devpriv->ai_scan_count--; + async->events |= COMEDI_CB_EOS; + } + } + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_scan_count == 0) { + /* End of acquisition. */ + events |= COMEDI_CB_EOA; + } else { + /* More samples required, tell Comedi to block. */ + events |= COMEDI_CB_BLOCK; + } + async->events |= events; + if ((async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | + COMEDI_CB_OVERFLOW)) != 0) { + /* disable hardware conversions */ + pci230_ai_stop(dev, s); + } else { + /* update FIFO interrupt trigger level */ + pci230_ai_update_fifo_trigger_level(dev, s); + } +} + static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci230_private *devpriv = dev->private; unsigned int i, chan, range, diff; unsigned int res_mask; unsigned short adccon, adcen; @@ -2386,14 +2272,10 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* Get number of scans required. */ - if (cmd->stop_src == TRIG_COUNT) { + if (cmd->stop_src == TRIG_COUNT) devpriv->ai_scan_count = cmd->stop_arg; - devpriv->ai_continuous = 0; - } else { - /* TRIG_NONE, user calls cancel. */ + else /* TRIG_NONE, user calls cancel */ devpriv->ai_scan_count = 0; - devpriv->ai_continuous = 1; - } devpriv->ai_scan_pos = 0; /* Position within scan. */ /* Steps; @@ -2537,91 +2419,19 @@ static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } } - if (cmd->start_src == TRIG_INT) { + if (cmd->start_src == TRIG_INT) s->async->inttrig = pci230_ai_inttrig_start; - } else { - /* TRIG_NOW */ + else /* TRIG_NOW */ pci230_ai_start(dev, s); - } return 0; } -static unsigned int divide_ns(uint64_t ns, unsigned int timebase, - unsigned int round_mode) -{ - uint64_t div; - unsigned int rem; - - div = ns; - rem = do_div(div, timebase); - round_mode &= TRIG_ROUND_MASK; - switch (round_mode) { - default: - case TRIG_ROUND_NEAREST: - div += (rem + (timebase / 2)) / timebase; - break; - case TRIG_ROUND_DOWN: - break; - case TRIG_ROUND_UP: - div += (rem + timebase - 1) / timebase; - break; - } - return div > UINT_MAX ? UINT_MAX : (unsigned int)div; -} - -/* Given desired period in ns, returns the required internal clock source - * and gets the initial count. */ -static unsigned int pci230_choose_clk_count(uint64_t ns, unsigned int *count, - unsigned int round_mode) -{ - unsigned int clk_src, cnt; - - for (clk_src = CLK_10MHZ;; clk_src++) { - cnt = divide_ns(ns, pci230_timebase[clk_src], round_mode); - if ((cnt <= 65536) || (clk_src == CLK_1KHZ)) - break; - - } - *count = cnt; - return clk_src; -} - -static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int round) -{ - unsigned int count; - unsigned int clk_src; - - clk_src = pci230_choose_clk_count(*ns, &count, round); - *ns = count * pci230_timebase[clk_src]; - return; -} - -static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct, - unsigned int mode, uint64_t ns, - unsigned int round) -{ - unsigned int clk_src; - unsigned int count; - - /* Set mode. */ - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, mode); - /* Determine clock source and count. */ - clk_src = pci230_choose_clk_count(ns, &count, round); - /* Program clock source. */ - outb(CLK_CONFIG(ct, clk_src), devpriv->iobase1 + PCI230_ZCLK_SCE); - /* Set initial count. */ - if (count >= 65536) - count = 0; - - i8254_write(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, count); -} - -static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct) +static int pci230_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - i8254_set_mode(devpriv->iobase1 + PCI230_Z2_CT_BASE, 0, ct, - I8254_MODE1); - /* Counter ct, 8254 mode 1, initial count not written. */ + pci230_ai_stop(dev, s); + return 0; } /* Interrupt handler */ @@ -2629,6 +2439,7 @@ static irqreturn_t pci230_interrupt(int irq, void *d) { unsigned char status_int, valid_status_int; struct comedi_device *dev = (struct comedi_device *)d; + struct pci230_private *devpriv = dev->private; struct comedi_subdevice *s; unsigned long irqflags; @@ -2688,369 +2499,327 @@ static irqreturn_t pci230_interrupt(int irq, void *d) return IRQ_HANDLED; } -static void pci230_handle_ao_nofifo(struct comedi_device *dev, - struct comedi_subdevice *s) +/* Check if PCI device matches a specific board. */ +static bool pci230_match_pci_board(const struct pci230_board *board, + struct pci_dev *pci_dev) { - short data; - int i, ret; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - - if (!devpriv->ao_continuous && (devpriv->ao_scan_count == 0)) - return; - + /* assume pci_dev->device != PCI_DEVICE_ID_INVALID */ + if (board->id != pci_dev->device) + return false; + if (board->min_hwver == 0) + return true; + /* Looking for a '+' model. First check length of registers. */ + if (pci_resource_len(pci_dev, 3) < 32) + return false; /* Not a '+' model. */ + /* TODO: temporarily enable PCI device and read the hardware version + * register. For now, assume it's okay. */ + return true; +} - for (i = 0; i < cmd->chanlist_len; i++) { - /* Read sample from Comedi's circular buffer. */ - ret = comedi_buf_get(s->async, &data); - if (ret == 0) { - s->async->events |= COMEDI_CB_OVERFLOW; - pci230_ao_stop(dev, s); - comedi_error(dev, "AO buffer underrun"); - return; - } - /* Write value to DAC. */ - pci230_ao_write_nofifo(dev, data, CR_CHAN(cmd->chanlist[i])); - } +/* Look for board matching PCI device. */ +static const struct pci230_board *pci230_find_pci_board(struct pci_dev *pci_dev) +{ + unsigned int i; - async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - if (!devpriv->ao_continuous) { - devpriv->ao_scan_count--; - if (devpriv->ao_scan_count == 0) { - /* End of acquisition. */ - async->events |= COMEDI_CB_EOA; - pci230_ao_stop(dev, s); - } - } + for (i = 0; i < ARRAY_SIZE(pci230_boards); i++) + if (pci230_match_pci_board(&pci230_boards[i], pci_dev)) + return &pci230_boards[i]; + return NULL; } -/* 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) +/* 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) { - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - unsigned int num_scans; - unsigned int room; - unsigned short dacstat; - unsigned int i, n; - unsigned int bytes_per_scan; - unsigned int events = 0; - int running; - - /* Get DAC FIFO status. */ - dacstat = inw(dev->iobase + PCI230_DACCON); + const struct pci230_board *thisboard = comedi_board(dev); + struct pci_dev *pci_dev = NULL; + int bus = it->options[0]; + int slot = it->options[1]; - /* Determine number of scans available in buffer. */ - bytes_per_scan = cmd->chanlist_len * sizeof(short); - num_scans = comedi_buf_read_n_available(async) / bytes_per_scan; - if (!devpriv->ao_continuous) { - /* Fixed number of scans. */ - if (num_scans > devpriv->ao_scan_count) - num_scans = devpriv->ao_scan_count; + 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; - if (devpriv->ao_scan_count == 0) { - /* End of acquisition. */ - events |= COMEDI_CB_EOA; - } - } - if (events == 0) { - /* Check for FIFO underrun. */ - if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) { - comedi_error(dev, "AO FIFO underrun"); - events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; - } - /* Check for buffer underrun if FIFO less than half full - * (otherwise there will be loads of "DAC FIFO not half full" - * interrupts). */ - if ((num_scans == 0) - && ((dacstat & PCI230P2_DAC_FIFO_HALF) == 0)) { - comedi_error(dev, "AO buffer underrun"); - events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + 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; } - if (events == 0) { - /* Determine how much room is in the FIFO (in samples). */ - if ((dacstat & PCI230P2_DAC_FIFO_FULL) != 0) - room = PCI230P2_DAC_FIFOROOM_FULL; - else if ((dacstat & PCI230P2_DAC_FIFO_HALF) != 0) - room = PCI230P2_DAC_FIFOROOM_HALFTOFULL; - else if ((dacstat & PCI230P2_DAC_FIFO_EMPTY) != 0) - room = PCI230P2_DAC_FIFOROOM_EMPTY; - else - room = PCI230P2_DAC_FIFOROOM_ONETOHALF; + dev_err(dev->class_dev, + "No supported board found! (req. bus %d, slot %d)\n", + bus, slot); + return NULL; +} - /* Convert room to number of scans that can be added. */ - room /= cmd->chanlist_len; - /* Determine number of scans to process. */ - if (num_scans > room) - num_scans = room; +static int pci230_alloc_private(struct comedi_device *dev) +{ + struct pci230_private *devpriv; - /* Process scans. */ - for (n = 0; n < num_scans; n++) { - for (i = 0; i < cmd->chanlist_len; i++) { - short datum; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - comedi_buf_get(async, &datum); - pci230_ao_write_fifo(dev, datum, - CR_CHAN(cmd->chanlist[i])); - } - } - events |= COMEDI_CB_EOS | COMEDI_CB_BLOCK; - if (!devpriv->ao_continuous) { - devpriv->ao_scan_count -= num_scans; - if (devpriv->ao_scan_count == 0) { - /* All data for the command has been written - * to FIFO. Set FIFO interrupt trigger level - * to 'empty'. */ - devpriv->daccon = (devpriv->daccon - & - ~PCI230P2_DAC_INT_FIFO_MASK) - | PCI230P2_DAC_INT_FIFO_EMPTY; - outw(devpriv->daccon, - dev->iobase + PCI230_DACCON); - } - } - /* Check if FIFO underrun occurred while writing to FIFO. */ - dacstat = inw(dev->iobase + PCI230_DACCON); - if ((dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) != 0) { - comedi_error(dev, "AO FIFO underrun"); - events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; - } - } - if ((events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) - != 0) { - /* Stopping AO due to completion or error. */ - pci230_ao_stop(dev, s); - running = 0; - } else { - running = 1; - } - async->events |= events; - return running; + spin_lock_init(&devpriv->isr_spinlock); + spin_lock_init(&devpriv->res_spinlock); + spin_lock_init(&devpriv->ai_stop_spinlock); + spin_lock_init(&devpriv->ao_stop_spinlock); + return 0; } -static void pci230_handle_ai(struct comedi_device *dev, - struct comedi_subdevice *s) +/* Common part of attach and auto_attach. */ +static int pci230_attach_common(struct comedi_device *dev, + struct pci_dev *pci_dev) { - unsigned int events = 0; - unsigned int status_fifo; - unsigned int i; - unsigned int todo; - unsigned int fifoamount; - struct comedi_async *async = s->async; - unsigned int scanlen = async->cmd.scan_end_arg; - - /* Determine number of samples to read. */ - if (devpriv->ai_continuous) { - 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)) { - todo = PCI230_ADC_FIFOLEVEL_HALFFULL; - } else { - todo = (devpriv->ai_scan_count * scanlen) - - devpriv->ai_scan_pos; - if (todo > PCI230_ADC_FIFOLEVEL_HALFFULL) - todo = PCI230_ADC_FIFOLEVEL_HALFFULL; + 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); - if (todo == 0) - return; + dev->board_name = thisboard->name; + rc = comedi_pci_enable(dev); + if (rc) + return rc; - fifoamount = 0; - for (i = 0; i < todo; i++) { - if (fifoamount == 0) { - /* Read FIFO state. */ - status_fifo = inw(dev->iobase + PCI230_ADCCON); + /* 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_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; + /* Read bits of DACCON register - only the output range. */ + devpriv->daccon = inw(dev->iobase + PCI230_DACCON) & PCI230_DAC_OR_MASK; + /* Read hardware version register and set extended function register + * if they exist. */ + if (pci_resource_len(pci_dev, 3) >= 32) { + unsigned short extfunc = 0; - if ((status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) != 0) { - /* Report error otherwise FIFO overruns will go - * unnoticed by the caller. */ - comedi_error(dev, "AI FIFO overrun"); - events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; - break; - } else if ((status_fifo & PCI230_ADC_FIFO_EMPTY) != 0) { - /* FIFO empty. */ - break; - } else if ((status_fifo & PCI230_ADC_FIFO_HALF) != 0) { - /* FIFO half full. */ - fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL; - } 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; - } - } + devpriv->hwver = inw(dev->iobase + PCI230P_HWVER); + if (devpriv->hwver < thisboard->min_hwver) { + dev_err(dev->class_dev, + "%s - bad hardware version - got %u, need %u\n", + dev->board_name, devpriv->hwver, + thisboard->min_hwver); + return -EIO; } - - /* Read sample and store in Comedi's circular buffer. */ - if (comedi_buf_put(async, pci230_ai_read(dev)) == 0) { - events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW; - comedi_error(dev, "AI buffer overflow"); - break; + if (devpriv->hwver > 0) { + if (!thisboard->have_dio) { + /* No DIO ports. Route counters' external gates + * to the EXTTRIG signal (PCI260+ pin 17). + * (Otherwise, they would be routed to DIO + * inputs PC0, PC1 and PC2 which don't exist + * on PCI260[+].) */ + extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG; + } + if ((thisboard->ao_chans > 0) + && (devpriv->hwver >= 2)) { + /* Enable DAC FIFO functionality. */ + extfunc |= PCI230P2_EXTFUNC_DACFIFO; + } } - fifoamount--; - devpriv->ai_scan_pos++; - if (devpriv->ai_scan_pos == scanlen) { - /* End of scan. */ - devpriv->ai_scan_pos = 0; - devpriv->ai_scan_count--; - async->events |= COMEDI_CB_EOS; + outw(extfunc, dev->iobase + PCI230P_EXTFUNC); + if ((extfunc & PCI230P2_EXTFUNC_DACFIFO) != 0) { + /* Temporarily enable DAC FIFO, reset it and disable + * FIFO wraparound. */ + outw(devpriv->daccon | PCI230P2_DAC_FIFO_EN + | PCI230P2_DAC_FIFO_RESET, + dev->iobase + PCI230_DACCON); + /* Clear DAC FIFO channel enable register. */ + outw(0, dev->iobase + PCI230P2_DACEN); + /* Disable DAC FIFO. */ + outw(devpriv->daccon, dev->iobase + PCI230_DACCON); } } + /* Disable board's interrupts. */ + outb(0, devpriv->iobase1 + 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(devpriv->adccon | PCI230_ADC_FIFO_RESET, + dev->iobase + PCI230_ADCCON); - if (!devpriv->ai_continuous && (devpriv->ai_scan_count == 0)) { - /* End of acquisition. */ - events |= COMEDI_CB_EOA; - } else { - /* More samples required, tell Comedi to block. */ - events |= COMEDI_CB_BLOCK; - } - async->events |= events; - - if ((async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) != 0) { - /* disable hardware conversions */ - pci230_ai_stop(dev, s); - } else { - /* update FIFO interrupt trigger level */ - pci230_ai_update_fifo_trigger_level(dev, s); + if (pci_dev->irq) { + rc = request_irq(pci_dev->irq, pci230_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (rc == 0) + dev->irq = pci_dev->irq; } -} - -static void pci230_ao_stop(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned long irqflags; - unsigned char intsrc; - int started; - struct comedi_cmd *cmd; - spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags); - started = test_and_clear_bit(AO_CMD_STARTED, &devpriv->state); - spin_unlock_irqrestore(&devpriv->ao_stop_spinlock, irqflags); - if (!started) - return; + rc = comedi_alloc_subdevices(dev, 3); + if (rc) + return rc; - - cmd = &s->async->cmd; - if (cmd->scan_begin_src == TRIG_TIMER) { - /* Stop scan rate generator. */ - pci230_cancel_ct(dev, 1); + s = &dev->subdevices[0]; + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND; + s->n_chan = thisboard->ai_chans; + s->maxdata = (1 << thisboard->ai_bits) - 1; + s->range_table = &pci230_ai_range; + s->insn_read = &pci230_ai_rinsn; + s->len_chanlist = 256; /* but there are restrictions. */ + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->do_cmd = &pci230_ai_cmd; + s->do_cmdtest = &pci230_ai_cmdtest; + s->cancel = pci230_ai_cancel; } - /* Determine interrupt source. */ - if (devpriv->hwver < 2) { - /* Not using DAC FIFO. Using CT1 interrupt. */ - intsrc = PCI230_INT_ZCLK_CT1; + s = &dev->subdevices[1]; + /* analog output subdevice */ + if (thisboard->ao_chans > 0) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = thisboard->ao_chans; + 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; + if (dev->irq) { + dev->write_subdev = s; + s->subdev_flags |= SDF_CMD_WRITE; + s->do_cmd = &pci230_ao_cmd; + s->do_cmdtest = &pci230_ao_cmdtest; + s->cancel = pci230_ao_cancel; + } } else { - /* Using DAC FIFO interrupt. */ - intsrc = PCI230P2_INT_DAC; - } - /* Disable interrupt and wait for interrupt routine to finish running - * unless we are called from the interrupt routine. */ - spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - devpriv->int_en &= ~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); + s->type = COMEDI_SUBD_UNUSED; } - spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); - if (devpriv->hwver >= 2) { - /* Using DAC FIFO. Reset FIFO, clear underrun error, - * disable FIFO. */ - devpriv->daccon &= PCI230_DAC_OR_MASK; - outw(devpriv->daccon | PCI230P2_DAC_FIFO_RESET - | PCI230P2_DAC_FIFO_UNDERRUN_CLEAR, - dev->iobase + PCI230_DACCON); + s = &dev->subdevices[2]; + /* digital i/o subdevice */ + if (thisboard->have_dio) { + rc = subdev_8255_init(dev, s, NULL, + devpriv->iobase1 + PCI230_PPI_X_BASE); + if (rc) + return rc; + } else { + s->type = COMEDI_SUBD_UNUSED; } - /* Release resources. */ - put_all_resources(dev, OWNER_AOCMD); + return 0; } -static int pci230_ao_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +static int pci230_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - pci230_ao_stop(dev, s); - return 0; + 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 void pci230_ai_stop(struct comedi_device *dev, - struct comedi_subdevice *s) +static int pci230_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - unsigned long irqflags; - struct comedi_cmd *cmd; - int started; - - spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags); - started = test_and_clear_bit(AI_CMD_STARTED, &devpriv->state); - spin_unlock_irqrestore(&devpriv->ai_stop_spinlock, irqflags); - if (!started) - return; + 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)); - cmd = &s->async->cmd; - if (cmd->convert_src == TRIG_TIMER) { - /* Stop conversion rate generator. */ - pci230_cancel_ct(dev, 2); - } - if (cmd->scan_begin_src != TRIG_FOLLOW) { - /* Stop scan period monostable. */ - pci230_cancel_ct(dev, 0); - } + rc = pci230_alloc_private(dev); + if (rc) + return rc; - spin_lock_irqsave(&devpriv->isr_spinlock, irqflags); - /* 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; - 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); + 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; } - spin_unlock_irqrestore(&devpriv->isr_spinlock, irqflags); + /* + * 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); +} - /* Reset FIFO, disable FIFO and set start conversion source to none. - * Keep se/diff and bip/uni settings */ - devpriv->adccon = (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); +static void pci230_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); - /* Release resources. */ - put_all_resources(dev, OWNER_AICMD); + if (dev->irq) + free_irq(dev->irq, dev); + comedi_pci_disable(dev); + if (pcidev) + pci_dev_put(pcidev); } -static int pci230_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +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), +}; + +static int amplc_pci230_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - pci230_ai_stop(dev, s); - return 0; + return comedi_pci_auto_config(dev, &lc_pci230_driver, + id->driver_data); } +static const struct pci_device_id amplc_pci230_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, amplc_pci230_pci_table); + +static struct pci_driver amplc_pci230_pci_driver = { + .name = "amplc_pci230", + .id_table = amplc_pci230_pci_table, + .probe = amplc_pci230_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +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_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/amplc_pci263.c b/drivers/staging/comedi/drivers/amplc_pci263.c new file mode 100644 index 00000000000..93ed03ee416 --- /dev/null +++ b/drivers/staging/comedi/drivers/amplc_pci263.c @@ -0,0 +1,120 @@ +/* + comedi/drivers/amplc_pci263.c + Driver for Amplicon PCI263 relay board. + + Copyright (C) 2002 MEV Ltd. <http://www.mev.co.uk/> + + 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: amplc_pci263 +Description: Amplicon PCI263 +Author: Ian Abbott <abbotti@mev.co.uk> +Devices: [Amplicon] PCI263 (amplc_pci263) +Updated: Fri, 12 Apr 2013 15:19:36 +0100 +Status: works + +Configuration options: not applicable, uses PCI auto config + +The board appears as one subdevice, with 16 digital outputs, each +connected to a reed-relay. Relay contacts are closed when output is 1. +The state of the outputs can be read. +*/ + +#include <linux/module.h> +#include <linux/pci.h> + +#include "../comedidev.h" + +#define PCI263_DRIVER_NAME "amplc_pci263" + +/* PCI263 PCI configuration register information */ +#define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c + +static int pci263_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase); + outb((s->state >> 8) & 0xff, dev->iobase + 1); + } + + data[1] = s->state; + + return insn->n; +} + +static int pci263_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pci_dev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + int ret; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pci_dev, 2); + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + s = &dev->subdevices[0]; + /* digital output subdevice */ + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pci263_do_insn_bits; + /* read initial relay state */ + s->state = inb(dev->iobase) | (inb(dev->iobase + 1) << 8); + + return 0; +} + +static struct comedi_driver amplc_pci263_driver = { + .driver_name = PCI263_DRIVER_NAME, + .module = THIS_MODULE, + .auto_attach = pci263_auto_attach, + .detach = comedi_pci_disable, +}; + +static const struct pci_device_id pci263_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) }, + {0} +}; +MODULE_DEVICE_TABLE(pci, pci263_pci_table); + +static int amplc_pci263_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &lc_pci263_driver, + id->driver_data); +} + +static struct pci_driver amplc_pci263_pci_driver = { + .name = PCI263_DRIVER_NAME, + .id_table = pci263_pci_table, + .probe = &lc_pci263_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(amplc_pci263_driver, amplc_pci263_pci_driver); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi driver for Amplicon PCI263 relay board"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index e0ac825ea58..e03dd6e7141 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -1,47 +1,39 @@ /* - comedi/drivers/c6xdigio.c - - Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. - (http://robot0.ge.uiuc.edu/~spong/mecha/) - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Dan Block - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - + * c6xdigio.c + * Hardware driver for Mechatronic Systems Inc. C6x_DIGIO DSP daughter card. + * http://web.archive.org/web/%2A/http://robot0.ge.uiuc.edu/~spong/mecha/ + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Dan Block + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -/* -Driver: c6xdigio -Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card -Author: Dan Block -Status: unknown -Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio) -Updated: Sun Nov 20 20:18:34 EST 2005 - -This driver will not work with a 2.4 kernel. -http://robot0.ge.uiuc.edu/~spong/mecha/ -*/ +/* + * Driver: c6xdigio + * Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card + * Author: Dan Block + * Status: unknown + * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio] + * Updated: Sun Nov 20 20:18:34 EST 2005 + * + * Configuration Options: + * [0] - base address + */ #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/mm.h> #include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/timex.h> #include <linux/timer.h> @@ -50,372 +42,195 @@ http://robot0.ge.uiuc.edu/~spong/mecha/ #include "../comedidev.h" -static u8 ReadByteFromHwPort(unsigned long addr) -{ - u8 result = inb(addr); - return result; -} - -static void WriteByteToHwPort(unsigned long addr, u8 val) -{ - outb_p(val, addr); -} - -#define C6XDIGIO_SIZE 3 - /* - * port offsets + * Register I/O map */ -#define C6XDIGIO_PARALLEL_DATA 0 -#define C6XDIGIO_PARALLEL_STATUS 1 -#define C6XDIGIO_PARALLEL_CONTROL 2 -struct pwmbitstype { - unsigned sb0:2; - unsigned sb1:2; - unsigned sb2:2; - unsigned sb3:2; - unsigned sb4:2; -}; -union pwmcmdtype { - unsigned cmd; /* assuming here that int is 32bit */ - struct pwmbitstype bits; -}; -struct encbitstype { - unsigned sb0:3; - unsigned sb1:3; - unsigned sb2:3; - unsigned sb3:3; - unsigned sb4:3; - unsigned sb5:3; - unsigned sb6:3; - unsigned sb7:3; -}; -union encvaluetype { - unsigned value; - struct encbitstype bits; -}; +#define C6XDIGIO_DATA_REG 0x00 +#define C6XDIGIO_DATA_CHAN(x) (((x) + 1) << 4) +#define C6XDIGIO_DATA_PWM (1 << 5) +#define C6XDIGIO_DATA_ENCODER (1 << 6) +#define C6XDIGIO_STATUS_REG 0x01 +#define C6XDIGIO_CTRL_REG 0x02 #define C6XDIGIO_TIME_OUT 20 -static int c6xdigio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int c6xdigio_detach(struct comedi_device *dev); -struct comedi_driver driver_c6xdigio = { - .driver_name = "c6xdigio", - .module = THIS_MODULE, - .attach = c6xdigio_attach, - .detach = c6xdigio_detach, -}; - -static void C6X_pwmInit(unsigned long baseAddr) +static int c6xdigio_chk_status(struct comedi_device *dev, unsigned long context) { + unsigned int status; int timeout = 0; -/* printk("Inside C6X_pwmInit\n"); */ - - WriteByteToHwPort(baseAddr, 0x70); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { + do { + status = inb(dev->iobase + C6XDIGIO_STATUS_REG); + if ((status & 0x80) != context) + return 0; timeout++; - } - - WriteByteToHwPort(baseAddr, 0x74); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - - WriteByteToHwPort(baseAddr, 0x70); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } + } while (timeout < C6XDIGIO_TIME_OUT); + return -EBUSY; } -static void C6X_pwmOutput(unsigned long baseAddr, unsigned channel, int value) +static int c6xdigio_write_data(struct comedi_device *dev, + unsigned int val, unsigned int status) { - unsigned ppcmd; - union pwmcmdtype pwm; - int timeout = 0; - unsigned tmp; - - /* printk("Inside C6X_pwmOutput\n"); */ - - pwm.cmd = value; - if (pwm.cmd > 498) - pwm.cmd = 498; - if (pwm.cmd < 2) - pwm.cmd = 2; - - if (channel == 0) { - ppcmd = 0x28; - } else { /* if channel == 1 */ - ppcmd = 0x30; - } /* endif */ - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb0); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb1 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + outb_p(val, dev->iobase + C6XDIGIO_DATA_REG); + return c6xdigio_chk_status(dev, status); +} - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb2); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } +static int c6xdigio_get_encoder_bits(struct comedi_device *dev, + unsigned int *bits, + unsigned int cmd, + unsigned int status) +{ + unsigned int val; - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb3 + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + val = inb(dev->iobase + C6XDIGIO_STATUS_REG); + val >>= 3; + val &= 0x07; - WriteByteToHwPort(baseAddr, ppcmd + pwm.bits.sb4); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + *bits = val; - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + return c6xdigio_write_data(dev, cmd, status); +} +static void c6xdigio_pwm_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) +{ + unsigned int cmd = C6XDIGIO_DATA_PWM | C6XDIGIO_DATA_CHAN(chan); + unsigned int bits; + + if (val > 498) + val = 498; + if (val < 2) + val = 2; + + bits = (val >> 0) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 2) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 4) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + bits = (val >> 6) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (1 << 2), 0x80); + bits = (val >> 8) & 0x03; + c6xdigio_write_data(dev, cmd | bits | (0 << 2), 0x00); + + c6xdigio_write_data(dev, 0x00, 0x80); } -static int C6X_encInput(unsigned long baseAddr, unsigned channel) +static int c6xdigio_encoder_read(struct comedi_device *dev, + unsigned int chan) { - unsigned ppcmd; - union encvaluetype enc; - int timeout = 0; - int tmp; + unsigned int cmd = C6XDIGIO_DATA_ENCODER | C6XDIGIO_DATA_CHAN(chan); + unsigned int val = 0; + unsigned int bits; - /* printk("Inside C6X_encInput\n"); */ + c6xdigio_write_data(dev, cmd, 0x00); - enc.value = 0; - if (channel == 0) - ppcmd = 0x48; - else - ppcmd = 0x50; + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 0); - WriteByteToHwPort(baseAddr, ppcmd); - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 3); - enc.bits.sb0 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb1 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb2 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb3 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb4 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb5 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb6 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd + 0x4); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } - enc.bits.sb7 = ((ReadByteFromHwPort(baseAddr + 1) >> 3) & 0x7); - WriteByteToHwPort(baseAddr, ppcmd); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x0) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 6); - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - tmp = ReadByteFromHwPort(baseAddr + 1); - while (((tmp & 0x80) == 0x80) && (timeout < C6XDIGIO_TIME_OUT)) { - tmp = ReadByteFromHwPort(baseAddr + 1); - timeout++; - } + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 9); - return enc.value ^ 0x800000; -} + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 12); -static void C6X_encResetAll(unsigned long baseAddr) -{ - unsigned timeout = 0; + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 15); -/* printk("Inside C6X_encResetAll\n"); */ + c6xdigio_get_encoder_bits(dev, &bits, cmd | (1 << 2), 0x80); + val |= (bits << 18); - WriteByteToHwPort(baseAddr, 0x68); - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x6C); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x68); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x0) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } - WriteByteToHwPort(baseAddr, 0x0); - timeout = 0; - while (((ReadByteFromHwPort(baseAddr + 1) & 0x80) == 0x80) - && (timeout < C6XDIGIO_TIME_OUT)) { - timeout++; - } -} + c6xdigio_get_encoder_bits(dev, &bits, cmd | (0 << 2), 0x00); + val |= (bits << 21); -static int c6xdigio_pwmo_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - printk("c6xdigio_pwmo_insn_read %x\n", insn->n); - return insn->n; + c6xdigio_write_data(dev, 0x00, 0x80); + + return val; } -static int c6xdigio_pwmo_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int c6xdigio_pwm_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = (s->state >> (16 * chan)) & 0xffff; int i; - int chan = CR_CHAN(insn->chanspec); - /* printk("c6xdigio_pwmo_insn_write %x\n", insn->n); */ for (i = 0; i < insn->n; i++) { - C6X_pwmOutput(dev->iobase, chan, data[i]); - /* devpriv->ao_readback[chan] = data[i]; */ + val = data[i]; + c6xdigio_pwm_write(dev, chan, val); } - return i; + + /* + * There are only 2 PWM channels and they have a maxdata of 500. + * Instead of allocating private data to save the values in for + * readback this driver just packs the values for the two channels + * in the s->state. + */ + s->state &= (0xffff << (16 * chan)); + s->state |= (val << (16 * chan)); + + return insn->n; } -/* static int c6xdigio_ei_init_insn_read(struct comedi_device *dev, */ -/* struct comedi_subdevice *s, */ -/* struct comedi_insn *insn, */ -/* unsigned int *data) */ -/* { */ -/* printk("c6xdigio_ei_init_insn_read %x\n", insn->n); */ -/* return insn->n; */ -/* } */ - -/* static int c6xdigio_ei_init_insn_write(struct comedi_device *dev, */ -/* struct comedi_subdevice *s, */ -/* struct comedi_insn *insn, */ -/* unsigned int *data) */ -/* { */ -/* int i; */ -/* int chan = CR_CHAN(insn->chanspec); */ - /* *//* C6X_encResetAll( dev->iobase ); */ - /* *//* return insn->n; */ -/* } */ - -static int c6xdigio_ei_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int c6xdigio_pwm_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* printk("c6xdigio_ei__insn_read %x\n", insn->n); */ - int n; - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + val = (s->state >> (16 * chan)) & 0xffff; - for (n = 0; n < insn->n; n++) - data[n] = (C6X_encInput(dev->iobase, chan) & 0xffffff); + for (i = 0; i < insn->n; i++) + data[i] = val; - return n; + return insn->n; } -static void board_init(struct comedi_device *dev) +static int c6xdigio_encoder_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - /* printk("Inside board_init\n"); */ + for (i = 0; i < insn->n; i++) { + val = c6xdigio_encoder_read(dev, chan); - C6X_pwmInit(dev->iobase); - C6X_encResetAll(dev->iobase); + /* munge two's complement value to offset binary */ + data[i] = comedi_offset_munge(s, val); + } + return insn->n; } -/* static void board_halt(struct comedi_device *dev) { */ -/* C6X_pwmInit(dev->iobase); */ -/* } */ - -/* - options[0] - I/O port - options[1] - irq - options[2] - number of encoder chips installed - */ +static void c6xdigio_init(struct comedi_device *dev) +{ + /* Initialize the PWM */ + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x74, 0x80); + c6xdigio_write_data(dev, 0x70, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); + + /* Reset the encoders */ + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x6c, 0x80); + c6xdigio_write_data(dev, 0x68, 0x00); + c6xdigio_write_data(dev, 0x00, 0x80); +} static const struct pnp_device_id c6xdigio_pnp_tbl[] = { /* Standard LPT Printer Port */ @@ -433,103 +248,60 @@ static struct pnp_driver c6xdigio_pnp_driver = { static int c6xdigio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int result = 0; - unsigned long iobase; - unsigned int irq; struct comedi_subdevice *s; + int ret; - iobase = it->options[0]; - printk("comedi%d: c6xdigio: 0x%04lx\n", dev->minor, iobase); - if (!request_region(iobase, C6XDIGIO_SIZE, "c6xdigio")) { - printk("comedi%d: I/O port conflict\n", dev->minor); - return -EIO; - } - dev->iobase = iobase; - dev->board_name = "c6xdigio"; + ret = comedi_request_region(dev, it->options[0], 0x03); + if (ret) + return ret; - result = alloc_subdevices(dev, 2); /* 3 with encoder_init write */ - if (result < 0) - return result; + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; /* Make sure that PnP ports get activated */ pnp_register_driver(&c6xdigio_pnp_driver); - irq = it->options[1]; - if (irq > 0) - printk("comedi%d: irq = %u ignored\n", dev->minor, irq); - else if (irq == 0) - printk("comedi%d: no irq\n", dev->minor); - - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* pwm output subdevice */ - s->type = COMEDI_SUBD_AO; /* Not sure what to put here */ - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_pwmo; */ - s->insn_read = c6xdigio_pwmo_insn_read; - s->insn_write = c6xdigio_pwmo_insn_write; - s->maxdata = 500; - s->range_table = &range_bipolar10; /* A suitable lie */ - - s = dev->subdevices + 1; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 500; + s->range_table = &range_unknown; + s->insn_write = c6xdigio_pwm_insn_write; + s->insn_read = c6xdigio_pwm_insn_read; + + s = &dev->subdevices[1]; /* encoder (counter) subdevice */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_LSAMPL; - s->n_chan = 2; - /* s->trig[0] = c6xdigio_ei; */ - s->insn_read = c6xdigio_ei_insn_read; - s->maxdata = 0xffffff; - s->range_table = &range_unknown; - - /* s = dev->subdevices + 2; */ - /* pwm output subdevice */ - /* s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here */ - /* s->subdev_flags = SDF_WRITEABLE; */ - /* s->n_chan = 1; */ - /* s->trig[0] = c6xdigio_ei_init; */ - /* s->insn_read = c6xdigio_ei_init_insn_read; */ - /* s->insn_write = c6xdigio_ei_init_insn_write; */ - /* s->maxdata = 0xFFFF; // Really just a don't care */ - /* s->range_table = &range_unknown; // Not sure what to put here */ + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_LSAMPL; + s->n_chan = 2; + s->maxdata = 0xffffff; + s->range_table = &range_unknown; + s->insn_read = c6xdigio_encoder_insn_read; /* I will call this init anyway but more than likely the DSP board */ /* will not be connected when device driver is loaded. */ - board_init(dev); + c6xdigio_init(dev); return 0; } -static int c6xdigio_detach(struct comedi_device *dev) +static void c6xdigio_detach(struct comedi_device *dev) { - /* board_halt(dev); may not need this */ - - printk("comedi%d: c6xdigio: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, C6XDIGIO_SIZE); - - /* Not using IRQ so I am not sure if I need this */ - if (dev->irq) - free_irq(dev->irq, dev); - + comedi_legacy_detach(dev); pnp_unregister_driver(&c6xdigio_pnp_driver); - - return 0; } -static int __init driver_c6xdigio_init_module(void) -{ - return comedi_driver_register(&driver_c6xdigio); -} - -static void __exit driver_c6xdigio_cleanup_module(void) -{ - comedi_driver_unregister(&driver_c6xdigio); -} - -module_init(driver_c6xdigio_init_module); -module_exit(driver_c6xdigio_cleanup_module); +static struct comedi_driver c6xdigio_driver = { + .driver_name = "c6xdigio", + .module = THIS_MODULE, + .attach = c6xdigio_attach, + .detach = c6xdigio_detach, +}; +module_comedi_driver(c6xdigio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for the C6x_DIGIO DSP daughter card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 8a1b8a7fa15..eb1b92d72e8 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -15,9 +15,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + PCMCIA support code for this driver is adapted from the dummy_cs.c + driver of the Linux PCMCIA Card Services package. + + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. */ /* @@ -31,15 +34,16 @@ Status: experimental */ +#include <linux/module.h> #include <linux/interrupt.h> -#include <linux/slab.h> -#include "../comedidev.h" #include <linux/delay.h> -#include <linux/pci.h> + +#include "../comedidev.h" #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> +#include "comedi_fc.h" #include "8253.h" #define DAS16CS_SIZE 18 @@ -59,436 +63,103 @@ struct das16cs_board { int device_id; int n_ao_chans; }; + static const struct das16cs_board das16cs_boards[] = { { - .device_id = 0x0000, /* unknown */ - .name = "PC-CARD DAS16/16", - .n_ao_chans = 0, - }, - { - .device_id = 0x0039, - .name = "PC-CARD DAS16/16-AO", - .n_ao_chans = 2, - }, - { - .device_id = 0x4009, - .name = "PCM-DAS16s/16", - .n_ao_chans = 0, - }, + .name = "PC-CARD DAS16/16-AO", + .device_id = 0x0039, + .n_ao_chans = 2, + }, { + .name = "PCM-DAS16s/16", + .device_id = 0x4009, + .n_ao_chans = 0, + }, { + .name = "PC-CARD DAS16/16", + .device_id = 0x0000, /* unknown */ + .n_ao_chans = 0, + }, }; -#define n_boards ARRAY_SIZE(das16cs_boards) -#define thisboard ((const struct das16cs_board *)dev->board_ptr) - struct das16cs_private { - struct pcmcia_device *link; - unsigned int ao_readback[2]; unsigned short status1; unsigned short status2; }; -#define devpriv ((struct das16cs_private *)dev->private) - -static int das16cs_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int das16cs_detach(struct comedi_device *dev); -static struct comedi_driver driver_das16cs = { - .driver_name = "cb_das16_cs", - .module = THIS_MODULE, - .attach = das16cs_attach, - .detach = das16cs_detach, -}; - -static struct pcmcia_device *cur_dev = NULL; - -static const struct comedi_lrange das16cs_ai_range = { 4, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - } -}; - -static irqreturn_t das16cs_interrupt(int irq, void *d); -static int das16cs_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16cs_ai_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int das16cs_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int das16cs_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16cs_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16cs_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16cs_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int das16cs_timer_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int das16cs_timer_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -static const struct das16cs_board *das16cs_probe(struct comedi_device *dev, - struct pcmcia_device *link) -{ - int i; - - for (i = 0; i < n_boards; i++) { - if (das16cs_boards[i].device_id == link->card_id) - return das16cs_boards + i; - } - - printk("unknown board!\n"); - - return NULL; -} - -static int das16cs_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pcmcia_device *link; - struct comedi_subdevice *s; - int ret; - int i; - - printk("comedi%d: cb_das16_cs: ", dev->minor); - - link = cur_dev; /* XXX hack */ - if (!link) - return -EIO; - - dev->iobase = link->resource[0]->start; - printk("I/O base=0x%04lx ", dev->iobase); - - printk("fingerprint:\n"); - for (i = 0; i < 48; i += 2) - printk("%04x ", inw(dev->iobase + i)); - - printk("\n"); - - ret = request_irq(link->irq, das16cs_interrupt, - IRQF_SHARED, "cb_das16_cs", dev); - if (ret < 0) - return ret; - - dev->irq = link->irq; - - printk("irq=%u ", dev->irq); - - dev->board_ptr = das16cs_probe(dev, link); - if (!dev->board_ptr) - return -EIO; - - dev->board_name = thisboard->name; - - if (alloc_private(dev, sizeof(struct das16cs_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - s = dev->subdevices + 0; - dev->read_subdev = s; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; - s->n_chan = 16; - s->maxdata = 0xffff; - s->range_table = &das16cs_ai_range; - s->len_chanlist = 16; - s->insn_read = das16cs_ai_rinsn; - s->do_cmd = das16cs_ai_cmd; - s->do_cmdtest = das16cs_ai_cmdtest; - - s = dev->subdevices + 1; - /* analog output subdevice */ - if (thisboard->n_ao_chans) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->n_ao_chans; - s->maxdata = 0xffff; - s->range_table = &range_bipolar10; - s->insn_write = &das16cs_ao_winsn; - s->insn_read = &das16cs_ao_rinsn; - } - - s = dev->subdevices + 2; - /* digital i/o subdevice */ - if (1) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = das16cs_dio_insn_bits; - s->insn_config = das16cs_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - s = dev->subdevices + 3; - /* timer subdevice */ - if (0) { - s->type = COMEDI_SUBD_TIMER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 1; - s->maxdata = 0xff; - s->range_table = &range_unknown; - s->insn_read = das16cs_timer_insn_read; - s->insn_config = das16cs_timer_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; +static const struct comedi_lrange das16cs_ai_range = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), } +}; - printk("attached\n"); - - return 1; -} - -static int das16cs_detach(struct comedi_device *dev) +static int das16cs_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - printk("comedi%d: das16cs: remove\n", dev->minor); - - if (dev->irq) - free_irq(dev->irq, dev); + unsigned int status; - - return 0; + status = inw(dev->iobase + DAS16CS_MISC1); + if (status & 0x0080) + return 0; + return -EBUSY; } -static irqreturn_t das16cs_interrupt(int irq, void *d) -{ - /* struct comedi_device *dev = d; */ - return IRQ_HANDLED; -} - -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ static int das16cs_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct das16cs_private *devpriv = dev->private; + int chan = CR_CHAN(insn->chanspec); + int range = CR_RANGE(insn->chanspec); + int aref = CR_AREF(insn->chanspec); + int ret; int i; - int to; - int aref; - int range; - int chan; - static int range_bits[] = { 0x800, 0x000, 0x100, 0x200 }; - chan = CR_CHAN(insn->chanspec); - aref = CR_AREF(insn->chanspec); - range = CR_RANGE(insn->chanspec); - - outw(chan, dev->iobase + 2); + outw(chan, dev->iobase + DAS16CS_DIO_MUX); devpriv->status1 &= ~0xf320; devpriv->status1 |= (aref == AREF_DIFF) ? 0 : 0x0020; - outw(devpriv->status1, dev->iobase + 4); + outw(devpriv->status1, dev->iobase + DAS16CS_MISC1); devpriv->status2 &= ~0xff00; - devpriv->status2 |= range_bits[range]; - outw(devpriv->status2, dev->iobase + 6); - - for (i = 0; i < insn->n; i++) { - outw(0, dev->iobase); - -#define TIMEOUT 1000 - for (to = 0; to < TIMEOUT; to++) { - if (inw(dev->iobase + 4) & 0x0080) - break; - } - if (to == TIMEOUT) { - printk("cb_das16_cs: ai timeout\n"); - return -ETIME; - } - data[i] = (unsigned short)inw(dev->iobase + 0); + switch (range) { + case 0: + devpriv->status2 |= 0x800; + break; + case 1: + devpriv->status2 |= 0x000; + break; + case 2: + devpriv->status2 |= 0x100; + break; + case 3: + devpriv->status2 |= 0x200; + break; } + outw(devpriv->status2, dev->iobase + DAS16CS_MISC2); - return i; -} - -static int das16cs_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) -{ - return -EINVAL; -} - -static int das16cs_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int tmp; - - /* 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. */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) - return 1; - - /* step 2: make sure trigger sources are unique and mutually compatible */ - - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; - - if (err) - return 2; - - /* step 3: make sure arguments are trivially compatible */ - - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } -#define MAX_SPEED 10000 /* in nanoseconds */ -#define MIN_SPEED 1000000000 /* in nanoseconds */ + for (i = 0; i < insn->n; i++) { + outw(0, dev->iobase + DAS16CS_ADC_DATA); - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < MAX_SPEED) { - cmd->scan_begin_arg = MAX_SPEED; - err++; - } - if (cmd->scan_begin_arg > MIN_SPEED) { - cmd->scan_begin_arg = MIN_SPEED; - err++; - } - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - /* should specify multiple external triggers */ - if (cmd->scan_begin_arg > 9) { - cmd->scan_begin_arg = 9; - err++; - } - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < MAX_SPEED) { - cmd->convert_arg = MAX_SPEED; - err++; - } - if (cmd->convert_arg > MIN_SPEED) { - cmd->convert_arg = MIN_SPEED; - err++; - } - } else { - /* external trigger */ - /* see above */ - if (cmd->convert_arg > 9) { - cmd->convert_arg = 9; - err++; - } - } + ret = comedi_timeout(dev, s, insn, das16cs_ai_eoc, 0); + if (ret) + return ret; - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; + data[i] = inw(dev->iobase + DAS16CS_ADC_DATA); } - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg > 0x00ffffff) { - cmd->stop_arg = 0x00ffffff; - err++; - } - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer(100, &div1, &div2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - unsigned int div1 = 0, div2 = 0; - - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(100, &div1, &div2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } - - if (err) - return 4; - - return 0; + return i; } static int das16cs_ao_winsn(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 short status1; @@ -499,7 +170,7 @@ static int das16cs_ao_winsn(struct comedi_device *dev, devpriv->ao_readback[chan] = data[i]; d = data[i]; - outw(devpriv->status1, dev->iobase + 4); + outw(devpriv->status1, dev->iobase + DAS16CS_MISC1); udelay(1); status1 = devpriv->status1 & ~0xf; @@ -508,34 +179,33 @@ static int das16cs_ao_winsn(struct comedi_device *dev, else status1 |= 0x0008; -/* printk("0x%04x\n",status1);*/ - outw(status1, dev->iobase + 4); + outw(status1, dev->iobase + DAS16CS_MISC1); udelay(1); for (bit = 15; bit >= 0; bit--) { int b = (d >> bit) & 0x1; + b <<= 1; -/* printk("0x%04x\n",status1 | b | 0x0000);*/ - outw(status1 | b | 0x0000, dev->iobase + 4); + outw(status1 | b | 0x0000, dev->iobase + DAS16CS_MISC1); udelay(1); -/* printk("0x%04x\n",status1 | b | 0x0004);*/ - outw(status1 | b | 0x0004, dev->iobase + 4); + outw(status1 | b | 0x0004, dev->iobase + DAS16CS_MISC1); udelay(1); } -/* make high both DAC0CS and DAC1CS to load - new data and update analog output*/ - outw(status1 | 0x9, dev->iobase + 4); + /* + * Make both DAC0CS and DAC1CS high to load + * the new data and update analog the output + */ + outw(status1 | 0x9, dev->iobase + DAS16CS_MISC1); } 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 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); @@ -545,294 +215,158 @@ static int das16cs_ao_rinsn(struct comedi_device *dev, 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 das16cs_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - - outw(s->state, dev->iobase + 16); - } + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + DAS16CS_DIO); - /* on return, data[1] contains the value of the digital - * input and output lines. */ - data[1] = inw(dev->iobase + 16); + data[1] = inw(dev->iobase + DAS16CS_DIO); - return 2; + return insn->n; } static int das16cs_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); - int bits; + struct das16cs_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; if (chan < 4) - bits = 0x0f; + mask = 0x0f; else - bits = 0xf0; + mask = 0xf0; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; devpriv->status2 &= ~0x00c0; devpriv->status2 |= (s->io_bits & 0xf0) ? 0x0080 : 0; devpriv->status2 |= (s->io_bits & 0x0f) ? 0x0040 : 0; - outw(devpriv->status2, dev->iobase + 6); + outw(devpriv->status2, dev->iobase + DAS16CS_MISC2); return insn->n; } -static int das16cs_timer_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return -EINVAL; -} - -static int das16cs_timer_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static const void *das16cs_find_boardinfo(struct comedi_device *dev, + struct pcmcia_device *link) { - return -EINVAL; -} - -/* PCMCIA stuff */ - -/*====================================================================== - - The following pcmcia code for the pcm-das08 is adapted from the - dummy_cs.c driver of the Linux PCMCIA Card Services package. - - The initial developer of the original code is David A. Hinds - <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - -======================================================================*/ - -#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE) - -static void das16cs_pcmcia_config(struct pcmcia_device *link); -static void das16cs_pcmcia_release(struct pcmcia_device *link); -static int das16cs_pcmcia_suspend(struct pcmcia_device *p_dev); -static int das16cs_pcmcia_resume(struct pcmcia_device *p_dev); - -/* - The attach() and detach() entry points are used to create and destroy - "instances" of the driver, where each instance represents everything - needed to manage one actual PCMCIA card. -*/ - -static int das16cs_pcmcia_attach(struct pcmcia_device *); -static void das16cs_pcmcia_detach(struct pcmcia_device *); - -/* - You'll also need to prototype all the functions that will actually - be used to talk to your device. See 'memory_cs' for a good example - of a fully self-sufficient driver; the other drivers rely more or - less on other parts of the kernel. -*/ - -struct local_info_t { - struct pcmcia_device *link; - int stop; - struct bus_operations *bus; -}; - -/*====================================================================== - - das16cs_pcmcia_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - - The dev_link structure is initialized, but we don't actually - configure the card at this point -- we wait until we receive a - card insertion event. - -======================================================================*/ - -static int das16cs_pcmcia_attach(struct pcmcia_device *link) -{ - struct local_info_t *local; - - dev_dbg(&link->dev, "das16cs_pcmcia_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - local->link = link; - link->priv = local; - - cur_dev = link; - - das16cs_pcmcia_config(link); - - return 0; -} /* das16cs_pcmcia_attach */ - -static void das16cs_pcmcia_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "das16cs_pcmcia_detach\n"); - - ((struct local_info_t *)link->priv)->stop = 1; - das16cs_pcmcia_release(link); - /* This points to the parent struct local_info_t struct */ - kfree(link->priv); -} /* das16cs_pcmcia_detach */ - + const struct das16cs_board *board; + int i; -static int das16cs_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; + for (i = 0; i < ARRAY_SIZE(das16cs_boards); i++) { + board = &das16cs_boards[i]; + if (board->device_id == link->card_id) + return board; + } - return pcmcia_request_io(p_dev); + return NULL; } -static void das16cs_pcmcia_config(struct pcmcia_device *link) +static int das16cs_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + const struct das16cs_board *board; + struct das16cs_private *devpriv; + struct comedi_subdevice *s; int ret; - dev_dbg(&link->dev, "das16cs_pcmcia_config\n"); - - /* Do we need to allocate an interrupt? */ - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, das16cs_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } + board = das16cs_find_boardinfo(dev, link); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); + link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + ret = comedi_pcmcia_enable(dev, NULL); if (ret) - goto failed; + return ret; + dev->iobase = link->resource[0]->start; - return; + link->priv = dev; -failed: - das16cs_pcmcia_release(link); -} /* das16cs_pcmcia_config */ + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; -static void das16cs_pcmcia_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "das16cs_pcmcia_release\n"); - pcmcia_disable_device(link); -} /* das16cs_pcmcia_release */ + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; -static int das16cs_pcmcia_suspend(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; + s = &dev->subdevices[0]; + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; + s->n_chan = 16; + s->maxdata = 0xffff; + s->range_table = &das16cs_ai_range; + s->len_chanlist = 16; + s->insn_read = das16cs_ai_rinsn; + + s = &dev->subdevices[1]; + /* analog output subdevice */ + if (board->n_ao_chans) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + 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; + } else { + s->type = COMEDI_SUBD_UNUSED; + } - /* Mark the device as stopped, to block IO until later */ - local->stop = 1; + s = &dev->subdevices[2]; + /* digital i/o subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das16cs_dio_insn_bits; + s->insn_config = das16cs_dio_insn_config; return 0; -} /* das16cs_pcmcia_suspend */ - -static int das16cs_pcmcia_resume(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; +} - local->stop = 0; - return 0; -} /* das16cs_pcmcia_resume */ +static struct comedi_driver driver_das16cs = { + .driver_name = "cb_das16_cs", + .module = THIS_MODULE, + .auto_attach = das16cs_auto_attach, + .detach = comedi_pcmcia_disable, +}; -/*====================================================================*/ +static int das16cs_pcmcia_attach(struct pcmcia_device *link) +{ + return comedi_pcmcia_auto_config(link, &driver_das16cs); +} static const struct pcmcia_device_id das16cs_id_table[] = { PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x0039), PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4009), PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, das16cs_id_table); -MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); -MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16"); -MODULE_LICENSE("GPL"); -struct pcmcia_driver das16cs_driver = { - .probe = das16cs_pcmcia_attach, - .remove = das16cs_pcmcia_detach, - .suspend = das16cs_pcmcia_suspend, - .resume = das16cs_pcmcia_resume, - .id_table = das16cs_id_table, - .owner = THIS_MODULE, - .name = "cb_das16_cs", +static struct pcmcia_driver das16cs_driver = { + .name = "cb_das16_cs", + .owner = THIS_MODULE, + .id_table = das16cs_id_table, + .probe = das16cs_pcmcia_attach, + .remove = comedi_pcmcia_auto_unconfig, }; +module_comedi_pcmcia_driver(driver_das16cs, das16cs_driver); -static int __init init_das16cs_pcmcia_cs(void) -{ - pcmcia_register_driver(&das16cs_driver); - return 0; -} - -static void __exit exit_das16cs_pcmcia_cs(void) -{ - pr_debug("das16cs_pcmcia_cs: unloading\n"); - pcmcia_unregister_driver(&das16cs_driver); -} - -int __init init_module(void) -{ - int ret; - - ret = init_das16cs_pcmcia_cs(); - if (ret < 0) - return ret; - - return comedi_driver_register(&driver_das16cs); -} - -void __exit cleanup_module(void) -{ - exit_das16cs_pcmcia_cs(); - comedi_driver_unregister(&driver_das16cs); -} - -#else -static int __init driver_das16cs_init_module(void) -{ - return comedi_driver_register(&driver_das16cs); -} - -static void __exit driver_das16cs_cleanup_module(void) -{ - comedi_driver_unregister(&driver_das16cs); -} - -module_init(driver_das16cs_init_module); -module_exit(driver_das16cs_cleanup_module); -#endif /* CONFIG_PCMCIA */ +MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); +MODULE_DESCRIPTION("Comedi driver for Computer Boards PC-CARD DAS16/16"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 61968a505f2..7377da1aff7 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -19,16 +19,11 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: cb_pcidas -Description: MeasurementComputing PCI-DAS series with the AMCC S5933 PCI controller +Description: MeasurementComputing PCI-DAS series + with the AMCC S5933 PCI controller Author: Ivan Martinez <imr@oersted.dtu.dk>, Frank Mori Hess <fmhess@users.sourceforge.net> Updated: 2003-3-11 @@ -44,11 +39,7 @@ Status: The boards may be autocalibrated using the comedi_calibrate utility. -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration options: not applicable, uses PCI auto config For commands, the scanned channels must be consecutive (i.e. 4-5-6-7, 2-3-4,...), and must all have the same @@ -57,8 +48,8 @@ range and aref. AI Triggering: For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used. For 1602 series, the start_arg is interpreted as follows: - start_arg == 0 => gated triger (level high) - start_arg == CR_INVERT => gated triger (level low) + start_arg == 0 => gated trigger (level high) + start_arg == CR_INVERT => gated trigger (level low) start_arg == CR_EDGE => Rising edge start_arg == CR_EDGE | CR_INVERT => Falling edge For the other boards the trigger will be done on rising edge @@ -70,99 +61,80 @@ TODO: analog triggering on 1602 series */ -#include "../comedidev.h" +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> +#include "../comedidev.h" + #include "8253.h" #include "8255.h" #include "amcc_s5933.h" -#include "comedi_pci.h" #include "comedi_fc.h" -#undef CB_PCIDAS_DEBUG /* disable debugging code */ -/* #define CB_PCIDAS_DEBUG enable debugging code */ - -/* PCI vendor number of ComputerBoards/MeasurementComputing */ -#define PCI_VENDOR_ID_CB 0x1307 -#define TIMER_BASE 100 /* 10MHz master clock */ -#define AI_BUFFER_SIZE 1024 /* maximum fifo size of any supported board */ -#define AO_BUFFER_SIZE 1024 /* maximum fifo size of any supported board */ -#define NUM_CHANNELS_8800 8 -#define NUM_CHANNELS_7376 1 -#define NUM_CHANNELS_8402 2 -#define NUM_CHANNELS_DAC08 1 - -/* PCI-DAS base addresses */ - -/* indices of base address regions */ -#define S5933_BADRINDEX 0 -#define CONT_STAT_BADRINDEX 1 -#define ADC_FIFO_BADRINDEX 2 -#define PACER_BADRINDEX 3 -#define AO_BADRINDEX 4 -/* sizes of io regions */ -#define CONT_STAT_SIZE 10 -#define ADC_FIFO_SIZE 4 -#define PACER_SIZE 12 -#define AO_SIZE 4 +#define AI_BUFFER_SIZE 1024 /* max ai fifo size */ +#define AO_BUFFER_SIZE 1024 /* max ao fifo size */ +#define NUM_CHANNELS_8800 8 +#define NUM_CHANNELS_7376 1 +#define NUM_CHANNELS_8402 2 +#define NUM_CHANNELS_DAC08 1 /* Control/Status registers */ -#define INT_ADCFIFO 0 /* INTERRUPT / ADC FIFO register */ -#define INT_EOS 0x1 /* interrupt end of scan */ -#define INT_FHF 0x2 /* interrupt fifo half full */ -#define INT_FNE 0x3 /* interrupt fifo not empty */ -#define INT_MASK 0x3 /* mask of interrupt select bits */ -#define INTE 0x4 /* interrupt enable */ -#define DAHFIE 0x8 /* dac half full interrupt enable */ -#define EOAIE 0x10 /* end of acquisition interrupt enable */ -#define DAHFI 0x20 /* dac half full read status / write interrupt clear */ -#define EOAI 0x40 /* read end of acq. interrupt status / write clear */ -#define INT 0x80 /* read interrupt status / write clear */ -#define EOBI 0x200 /* read end of burst interrupt status */ -#define ADHFI 0x400 /* read half-full interrupt status */ -#define ADNEI 0x800 /* read fifo not empty interrupt latch status */ -#define ADNE 0x1000 /* read, fifo not empty (realtime, not latched) status */ -#define DAEMIE 0x1000 /* write, dac empty interrupt enable */ -#define LADFUL 0x2000 /* read fifo overflow / write clear */ -#define DAEMI 0x4000 /* dac fifo empty interrupt status / write clear */ - -#define ADCMUX_CONT 2 /* ADC CHANNEL MUX AND CONTROL register */ -#define BEGIN_SCAN(x) ((x) & 0xf) -#define END_SCAN(x) (((x) & 0xf) << 4) -#define GAIN_BITS(x) (((x) & 0x3) << 8) -#define UNIP 0x800 /* Analog front-end unipolar for range */ -#define SE 0x400 /* Inputs in single-ended mode */ -#define PACER_MASK 0x3000 /* pacer source bits */ -#define PACER_INT 0x1000 /* internal pacer */ -#define PACER_EXT_FALL 0x2000 /* external falling edge */ -#define PACER_EXT_RISE 0x3000 /* external rising edge */ -#define EOC 0x4000 /* adc not busy */ - -#define TRIG_CONTSTAT 4 /* TRIGGER CONTROL/STATUS register */ -#define SW_TRIGGER 0x1 /* software start trigger */ -#define EXT_TRIGGER 0x2 /* external start trigger */ -#define ANALOG_TRIGGER 0x3 /* external analog trigger */ -#define TRIGGER_MASK 0x3 /* mask of bits that determine start trigger */ -#define TGPOL 0x04 /* invert the edge/level of the external trigger (1602 only) */ -#define TGSEL 0x08 /* if set edge triggered, otherwise level trigerred (1602 only) */ -#define TGEN 0x10 /* enable external start trigger */ -#define BURSTE 0x20 /* burst mode enable */ -#define XTRCL 0x80 /* clear external trigger */ - -#define CALIBRATION_REG 6 /* CALIBRATION register */ -#define SELECT_8800_BIT 0x100 /* select 8800 caldac */ -#define SELECT_TRIMPOT_BIT 0x200 /* select ad7376 trim pot */ -#define SELECT_DAC08_BIT 0x400 /* select dac08 caldac */ +#define INT_ADCFIFO 0 /* INTERRUPT / ADC FIFO register */ +#define INT_EOS 0x1 /* int end of scan */ +#define INT_FHF 0x2 /* int fifo half full */ +#define INT_FNE 0x3 /* int fifo not empty */ +#define INT_MASK 0x3 /* mask of int select bits */ +#define INTE 0x4 /* int enable */ +#define DAHFIE 0x8 /* dac half full int enable */ +#define EOAIE 0x10 /* end of acq. int enable */ +#define DAHFI 0x20 /* dac half full status / clear */ +#define EOAI 0x40 /* end of acq. int status / clear */ +#define INT 0x80 /* int status / clear */ +#define EOBI 0x200 /* end of burst int status */ +#define ADHFI 0x400 /* half-full int status */ +#define ADNEI 0x800 /* fifo not empty int status (latch) */ +#define ADNE 0x1000 /* fifo not empty status (realtime) */ +#define DAEMIE 0x1000 /* dac empty int enable */ +#define LADFUL 0x2000 /* fifo overflow / clear */ +#define DAEMI 0x4000 /* dac fifo empty int status / clear */ + +#define ADCMUX_CONT 2 /* ADC CHANNEL MUX AND CONTROL reg */ +#define BEGIN_SCAN(x) ((x) & 0xf) +#define END_SCAN(x) (((x) & 0xf) << 4) +#define GAIN_BITS(x) (((x) & 0x3) << 8) +#define UNIP 0x800 /* Analog front-end unipolar mode */ +#define SE 0x400 /* Inputs in single-ended mode */ +#define PACER_MASK 0x3000 /* pacer source bits */ +#define PACER_INT 0x1000 /* int. pacer */ +#define PACER_EXT_FALL 0x2000 /* ext. falling edge */ +#define PACER_EXT_RISE 0x3000 /* ext. rising edge */ +#define EOC 0x4000 /* adc not busy */ + +#define TRIG_CONTSTAT 4 /* TRIGGER CONTROL/STATUS register */ +#define SW_TRIGGER 0x1 /* software start trigger */ +#define EXT_TRIGGER 0x2 /* ext. start trigger */ +#define ANALOG_TRIGGER 0x3 /* ext. analog trigger */ +#define TRIGGER_MASK 0x3 /* start trigger mask */ +#define TGPOL 0x04 /* invert trigger (1602 only) */ +#define TGSEL 0x08 /* edge/level trigerred (1602 only) */ +#define TGEN 0x10 /* enable external start trigger */ +#define BURSTE 0x20 /* burst mode enable */ +#define XTRCL 0x80 /* clear external trigger */ + +#define CALIBRATION_REG 6 /* CALIBRATION register */ +#define SELECT_8800_BIT 0x100 /* select 8800 caldac */ +#define SELECT_TRIMPOT_BIT 0x200 /* select ad7376 trim pot */ +#define SELECT_DAC08_BIT 0x400 /* select dac08 caldac */ #define CAL_SRC_BITS(x) (((x) & 0x7) << 11) -#define CAL_EN_BIT 0x4000 /* read calibration source instead of analog input channel 0 */ -#define SERIAL_DATA_IN_BIT 0x8000 /* serial data stream going to 8800 and 7376 */ +#define CAL_EN_BIT 0x4000 /* calibration source enable */ +#define SERIAL_DATA_IN_BIT 0x8000 /* serial data bit going to caldac */ + +#define DAC_CSR 0x8 /* dac control and status register */ +#define DACEN 0x02 /* dac enable */ +#define DAC_MODE_UPDATE_BOTH 0x80 /* update both dacs */ -#define DAC_CSR 0x8 /* dac control and status register */ -enum dac_csr_bits { - DACEN = 0x2, /* dac enable */ - DAC_MODE_UPDATE_BOTH = 0x80, /* update both dacs when dac0 is written */ -}; static inline unsigned int DAC_RANGE(unsigned int channel, unsigned int range) { return (range & 0x3) << (8 + 2 * (channel & 0x1)); @@ -174,27 +146,26 @@ static inline unsigned int DAC_RANGE_MASK(unsigned int channel) }; /* bits for 1602 series only */ -enum dac_csr_bits_1602 { - DAC_EMPTY = 0x1, /* dac fifo empty, read, write clear */ - DAC_START = 0x4, /* start/arm dac fifo operations */ - DAC_PACER_MASK = 0x18, /* bits that set dac pacer source */ - DAC_PACER_INT = 0x8, /* dac internal pacing */ - DAC_PACER_EXT_FALL = 0x10, /* dac external pacing, falling edge */ - DAC_PACER_EXT_RISE = 0x18, /* dac external pacing, rising edge */ -}; +#define DAC_EMPTY 0x1 /* fifo empty, read, write clear */ +#define DAC_START 0x4 /* start/arm fifo operations */ +#define DAC_PACER_MASK 0x18 /* bits that set pacer source */ +#define DAC_PACER_INT 0x8 /* int. pacing */ +#define DAC_PACER_EXT_FALL 0x10 /* ext. pacing, falling edge */ +#define DAC_PACER_EXT_RISE 0x18 /* ext. pacing, rising edge */ + static inline unsigned int DAC_CHAN_EN(unsigned int channel) { return 1 << (5 + (channel & 0x1)); /* enable channel 0 or 1 */ }; /* analog input fifo */ -#define ADCDATA 0 /* ADC DATA register */ -#define ADCFIFOCLR 2 /* ADC FIFO CLEAR */ +#define ADCDATA 0 /* ADC DATA register */ +#define ADCFIFOCLR 2 /* ADC FIFO CLEAR */ /* pacer, counter, dio registers */ -#define ADC8254 0 -#define DIO_8255 4 -#define DAC8254 8 +#define ADC8254 0 +#define DIO_8255 4 +#define DAC8254 8 /* analog output registers for 100x, 1200 series */ static inline unsigned int DAC_DATA_REG(unsigned int channel) @@ -203,50 +174,47 @@ static inline unsigned int DAC_DATA_REG(unsigned int channel) } /* analog output registers for 1602 series*/ -#define DACDATA 0 /* DAC DATA register */ -#define DACFIFOCLR 2 /* DAC FIFO CLEAR */ +#define DACDATA 0 /* DAC DATA register */ +#define DACFIFOCLR 2 /* DAC FIFO CLEAR */ + +#define IS_UNIPOLAR 0x4 /* unipolar range mask */ -/* bit in hexadecimal representation of range index that indicates unipolar input range */ -#define IS_UNIPOLAR 0x4 /* analog input ranges for most boards */ static const struct comedi_lrange cb_pcidas_ranges = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; /* pci-das1001 input ranges */ static const struct comedi_lrange cb_pcidas_alt_ranges = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01) - } + 8, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; /* analog output ranges */ static const struct comedi_lrange cb_pcidas_ao_ranges = { - 4, - { - BIP_RANGE(5), - BIP_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(10), - } + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } }; enum trimpot_model { @@ -254,575 +222,202 @@ enum trimpot_model { AD8402, }; +enum cb_pcidas_boardid { + BOARD_PCIDAS1602_16, + BOARD_PCIDAS1200, + BOARD_PCIDAS1602_12, + BOARD_PCIDAS1200_JR, + BOARD_PCIDAS1602_16_JR, + BOARD_PCIDAS1000, + BOARD_PCIDAS1001, + BOARD_PCIDAS1002, +}; + struct cb_pcidas_board { const char *name; - unsigned short device_id; - int ai_se_chans; /* Inputs in single-ended mode */ - int ai_diff_chans; /* Inputs in differential mode */ + int ai_nchan; /* Inputs in single-ended mode */ int ai_bits; /* analog input resolution */ int ai_speed; /* fastest conversion period in ns */ int ao_nchan; /* number of analog out channels */ int has_ao_fifo; /* analog output has fifo */ - int ao_scan_speed; /* analog output speed for 1602 series (for a scan, not conversion) */ + int ao_scan_speed; /* analog output scan speed for 1602 series */ int fifo_size; /* number of samples fifo can hold */ const struct comedi_lrange *ranges; enum trimpot_model trimpot; unsigned has_dac08:1; - unsigned has_ai_trig_gated:1; /* Tells if the AI trigger can be gated */ - unsigned has_ai_trig_invert:1; /* Tells if the AI trigger can be inverted */ + unsigned is_1602:1; }; static const struct cb_pcidas_board cb_pcidas_boards[] = { - { - .name = "pci-das1602/16", - .device_id = 0x1, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 2, - .has_ao_fifo = 1, - .ao_scan_speed = 10000, - .fifo_size = 512, - .ranges = &cb_pcidas_ranges, - .trimpot = AD8402, - .has_dac08 = 1, - .has_ai_trig_gated = 1, - .has_ai_trig_invert = 1, - }, - { - .name = "pci-das1200", - .device_id = 0xF, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 12, - .ai_speed = 3200, - .ao_nchan = 2, - .has_ao_fifo = 0, - .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, - .has_dac08 = 0, - .has_ai_trig_gated = 0, - .has_ai_trig_invert = 0, - }, - { - .name = "pci-das1602/12", - .device_id = 0x10, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 12, - .ai_speed = 3200, - .ao_nchan = 2, - .has_ao_fifo = 1, - .ao_scan_speed = 4000, - .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, - .has_dac08 = 0, - .has_ai_trig_gated = 1, - .has_ai_trig_invert = 1, - }, - { - .name = "pci-das1200/jr", - .device_id = 0x19, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 12, - .ai_speed = 3200, - .ao_nchan = 0, - .has_ao_fifo = 0, - .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, - .has_dac08 = 0, - .has_ai_trig_gated = 0, - .has_ai_trig_invert = 0, - }, - { - .name = "pci-das1602/16/jr", - .device_id = 0x1C, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 0, - .has_ao_fifo = 0, - .fifo_size = 512, - .ranges = &cb_pcidas_ranges, - .trimpot = AD8402, - .has_dac08 = 1, - .has_ai_trig_gated = 1, - .has_ai_trig_invert = 1, - }, - { - .name = "pci-das1000", - .device_id = 0x4C, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 12, - .ai_speed = 4000, - .ao_nchan = 0, - .has_ao_fifo = 0, - .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, - .has_dac08 = 0, - .has_ai_trig_gated = 0, - .has_ai_trig_invert = 0, - }, - { - .name = "pci-das1001", - .device_id = 0x1a, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 12, - .ai_speed = 6800, - .ao_nchan = 2, - .has_ao_fifo = 0, - .fifo_size = 1024, - .ranges = &cb_pcidas_alt_ranges, - .trimpot = AD7376, - .has_dac08 = 0, - .has_ai_trig_gated = 0, - .has_ai_trig_invert = 0, - }, - { - .name = "pci-das1002", - .device_id = 0x1b, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 12, - .ai_speed = 6800, - .ao_nchan = 2, - .has_ao_fifo = 0, - .fifo_size = 1024, - .ranges = &cb_pcidas_ranges, - .trimpot = AD7376, - .has_dac08 = 0, - .has_ai_trig_gated = 0, - .has_ai_trig_invert = 0, - }, + [BOARD_PCIDAS1602_16] = { + .name = "pci-das1602/16", + .ai_nchan = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .has_ao_fifo = 1, + .ao_scan_speed = 10000, + .fifo_size = 512, + .ranges = &cb_pcidas_ranges, + .trimpot = AD8402, + .has_dac08 = 1, + .is_1602 = 1, + }, + [BOARD_PCIDAS1200] = { + .name = "pci-das1200", + .ai_nchan = 16, + .ai_bits = 12, + .ai_speed = 3200, + .ao_nchan = 2, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + }, + [BOARD_PCIDAS1602_12] = { + .name = "pci-das1602/12", + .ai_nchan = 16, + .ai_bits = 12, + .ai_speed = 3200, + .ao_nchan = 2, + .has_ao_fifo = 1, + .ao_scan_speed = 4000, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + .is_1602 = 1, + }, + [BOARD_PCIDAS1200_JR] = { + .name = "pci-das1200/jr", + .ai_nchan = 16, + .ai_bits = 12, + .ai_speed = 3200, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + }, + [BOARD_PCIDAS1602_16_JR] = { + .name = "pci-das1602/16/jr", + .ai_nchan = 16, + .ai_bits = 16, + .ai_speed = 5000, + .fifo_size = 512, + .ranges = &cb_pcidas_ranges, + .trimpot = AD8402, + .has_dac08 = 1, + .is_1602 = 1, + }, + [BOARD_PCIDAS1000] = { + .name = "pci-das1000", + .ai_nchan = 16, + .ai_bits = 12, + .ai_speed = 4000, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + }, + [BOARD_PCIDAS1001] = { + .name = "pci-das1001", + .ai_nchan = 16, + .ai_bits = 12, + .ai_speed = 6800, + .ao_nchan = 2, + .fifo_size = 1024, + .ranges = &cb_pcidas_alt_ranges, + .trimpot = AD7376, + }, + [BOARD_PCIDAS1002] = { + .name = "pci-das1002", + .ai_nchan = 16, + .ai_bits = 12, + .ai_speed = 6800, + .ao_nchan = 2, + .fifo_size = 1024, + .ranges = &cb_pcidas_ranges, + .trimpot = AD7376, + }, }; -static DEFINE_PCI_DEVICE_TABLE(cb_pcidas_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0001) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000f) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0010) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0019) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001c) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x004c) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001a) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x001b) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table); - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct cb_pcidas_board *)dev->board_ptr) - -/* 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 cb_pcidas_private { - /* would be useful for a PCI device */ - struct pci_dev *pci_dev; - /* base addresses */ + /* base addresses */ 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 */ + /* divisors of master clock for analog input pacing */ unsigned int divisor1; unsigned int divisor2; - volatile unsigned int count; /* number of analog input samples remaining */ - volatile unsigned int adc_fifo_bits; /* bits to write to interrupt/adcfifo register */ - volatile unsigned int s5933_intcsr_bits; /* bits to write to amcc s5933 interrupt control/status register */ - volatile unsigned int ao_control_bits; /* bits to write to ao control and status register */ - short ai_buffer[AI_BUFFER_SIZE]; - short ao_buffer[AO_BUFFER_SIZE]; - /* divisors of master clock for analog output pacing */ + /* number of analog input samples remaining */ + unsigned int count; + /* bits to write to registers */ + unsigned int adc_fifo_bits; + unsigned int s5933_intcsr_bits; + unsigned int ao_control_bits; + /* fifo buffers */ + unsigned short ai_buffer[AI_BUFFER_SIZE]; + unsigned short ao_buffer[AO_BUFFER_SIZE]; + /* divisors of master clock for analog output pacing */ unsigned int ao_divisor1; unsigned int ao_divisor2; - volatile unsigned int ao_count; /* number of analog output samples remaining */ - int ao_value[2]; /* remember what the analog outputs are set to, to allow readback */ - unsigned int caldac_value[NUM_CHANNELS_8800]; /* for readback of caldac */ - unsigned int trimpot_value[NUM_CHANNELS_8402]; /* for readback of trimpot */ + /* 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; unsigned int calibration_source; }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct cb_pcidas_private *)dev->private) - -/* - * 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 int cb_pcidas_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int cb_pcidas_detach(struct comedi_device *dev); -static struct comedi_driver driver_cb_pcidas = { - .driver_name = "cb_pcidas", - .module = THIS_MODULE, - .attach = cb_pcidas_attach, - .detach = cb_pcidas_detach, -}; - -static int cb_pcidas_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int cb_pcidas_ao_readback_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int cb_pcidas_ai_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int cb_pcidas_ao_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int cb_pcidas_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *subdev, - unsigned int trig_num); -static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static irqreturn_t cb_pcidas_interrupt(int irq, void *d); -static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status); -static int cb_pcidas_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static int cb_pcidas_ao_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns, - int round_flags); -static int eeprom_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int caldac_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int caldac_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int trimpot_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int cb_pcidas_trimpot_write(struct comedi_device *dev, - unsigned int channel, unsigned int value); -static int trimpot_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dac08_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int dac08_write(struct comedi_device *dev, unsigned int value); -static int dac08_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int caldac_8800_write(struct comedi_device *dev, unsigned int address, - uint8_t value); -static int trimpot_7376_write(struct comedi_device *dev, uint8_t value); -static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, - uint8_t value); -static int nvram_read(struct comedi_device *dev, unsigned int address, - uint8_t *data); - static inline unsigned int cal_enable_bits(struct comedi_device *dev) { - return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); -} - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. - */ -static int cb_pcidas_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - struct pci_dev *pcidev = NULL; - int index; - int i; - - printk("comedi%d: cb_pcidas: ", dev->minor); - -/* - * Allocate the private structure area. - */ - if (alloc_private(dev, sizeof(struct cb_pcidas_private)) < 0) - return -ENOMEM; - -/* - * Probe the device to determine what device in the series it is. - */ - printk("\n"); - - for_each_pci_dev(pcidev) { - /* is it not a computer boards card? */ - if (pcidev->vendor != PCI_VENDOR_ID_CB) - continue; - /* loop through cards supported by this driver */ - for (index = 0; index < ARRAY_SIZE(cb_pcidas_boards); index++) { - if (cb_pcidas_boards[index].device_id != pcidev->device) - continue; - /* was a particular bus/slot requested? */ - if (it->options[0] || it->options[1]) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - devpriv->pci_dev = pcidev; - dev->board_ptr = cb_pcidas_boards + index; - goto found; - } - } - - printk("No supported ComputerBoards/MeasurementComputing card found on " - "requested position\n"); - return -EIO; - -found: - - printk("Found %s on bus %i, slot %i\n", cb_pcidas_boards[index].name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn)); - - /* - * Enable PCI device and reserve I/O ports. - */ - if (comedi_pci_enable(pcidev, "cb_pcidas")) { - printk(" Failed to enable PCI device and request regions\n"); - return -EIO; - } - /* - * Initialize devpriv->control_status and devpriv->adc_fifo to point to - * their base address. - */ - devpriv->s5933_config = - pci_resource_start(devpriv->pci_dev, S5933_BADRINDEX); - devpriv->control_status = - pci_resource_start(devpriv->pci_dev, CONT_STAT_BADRINDEX); - devpriv->adc_fifo = - pci_resource_start(devpriv->pci_dev, ADC_FIFO_BADRINDEX); - devpriv->pacer_counter_dio = - pci_resource_start(devpriv->pci_dev, PACER_BADRINDEX); - if (thisboard->ao_nchan) { - devpriv->ao_registers = - pci_resource_start(devpriv->pci_dev, AO_BADRINDEX); - } - /* disable and clear interrupts on amcc s5933 */ - outl(INTCSR_INBOX_INTR_STATUS, - devpriv->s5933_config + AMCC_OP_REG_INTCSR); - - /* get irq */ - if (request_irq(devpriv->pci_dev->irq, cb_pcidas_interrupt, - IRQF_SHARED, "cb_pcidas", dev)) { - printk(" unable to allocate irq %d\n", devpriv->pci_dev->irq); - return -EINVAL; - } - dev->irq = devpriv->pci_dev->irq; + struct cb_pcidas_private *devpriv = dev->private; - /* Initialize dev->board_name */ - dev->board_name = thisboard->name; - -/* - * Allocate the subdevice structures. - */ - if (alloc_subdevices(dev, 7) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* analog input subdevice */ - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; - /* WARNING: Number of inputs in differential mode is ignored */ - s->n_chan = thisboard->ai_se_chans; - s->len_chanlist = thisboard->ai_se_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = thisboard->ranges; - s->insn_read = cb_pcidas_ai_rinsn; - s->insn_config = ai_config_insn; - s->do_cmd = cb_pcidas_ai_cmd; - s->do_cmdtest = cb_pcidas_ai_cmdtest; - s->cancel = cb_pcidas_cancel; - - /* analog output subdevice */ - s = dev->subdevices + 1; - if (thisboard->ao_nchan) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; - s->n_chan = thisboard->ao_nchan; - /* analog out resolution is the same as analog input resolution, so use ai_bits */ - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = &cb_pcidas_ao_ranges; - s->insn_read = cb_pcidas_ao_readback_insn; - if (thisboard->has_ao_fifo) { - dev->write_subdev = s; - s->subdev_flags |= SDF_CMD_WRITE; - 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; - } - - /* 8255 */ - s = dev->subdevices + 2; - subdev_8255_init(dev, s, NULL, devpriv->pacer_counter_dio + DIO_8255); - - /* serial EEPROM, */ - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_MEMORY; - s->subdev_flags = SDF_READABLE | SDF_INTERNAL; - s->n_chan = 256; - s->maxdata = 0xff; - s->insn_read = eeprom_read_insn; - - /* 8800 caldac */ - s = dev->subdevices + 4; - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = NUM_CHANNELS_8800; - s->maxdata = 0xff; - s->insn_read = caldac_read_insn; - s->insn_write = caldac_write_insn; - for (i = 0; i < s->n_chan; i++) - caldac_8800_write(dev, i, s->maxdata / 2); - - /* trim potentiometer */ - s = dev->subdevices + 5; - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - if (thisboard->trimpot == AD7376) { - s->n_chan = NUM_CHANNELS_7376; - s->maxdata = 0x7f; - } else { - s->n_chan = NUM_CHANNELS_8402; - s->maxdata = 0xff; - } - s->insn_read = trimpot_read_insn; - s->insn_write = trimpot_write_insn; - for (i = 0; i < s->n_chan; i++) - cb_pcidas_trimpot_write(dev, i, s->maxdata / 2); - - /* dac08 caldac */ - s = dev->subdevices + 6; - if (thisboard->has_dac08) { - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = NUM_CHANNELS_DAC08; - s->insn_read = dac08_read_insn; - s->insn_write = dac08_write_insn; - s->maxdata = 0xff; - dac08_write(dev, s->maxdata / 2); - } else - s->type = COMEDI_SUBD_UNUSED; - - /* make sure mailbox 4 is empty */ - inl(devpriv->s5933_config + AMCC_OP_REG_IMB4); - /* Set bits to enable incoming mailbox interrupts on amcc s5933. */ - devpriv->s5933_intcsr_bits = - INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | - INTCSR_INBOX_FULL_INT; - /* clear and enable interrupt on amcc s5933 */ - outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, - devpriv->s5933_config + AMCC_OP_REG_INTCSR); - - return 1; + return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source); } -/* - * cb_pcidas_detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int cb_pcidas_detach(struct comedi_device *dev) +static int cb_pcidas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - printk("comedi%d: cb_pcidas: remove\n", dev->minor); + struct cb_pcidas_private *devpriv = dev->private; + unsigned int status; - if (devpriv) { - if (devpriv->s5933_config) { - /* disable and clear interrupts on amcc s5933 */ - outl(INTCSR_INBOX_INTR_STATUS, - devpriv->s5933_config + AMCC_OP_REG_INTCSR); -#ifdef CB_PCIDAS_DEBUG - printk("detaching, incsr is 0x%x\n", - inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR)); -#endif - } - } - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 2); - if (devpriv && devpriv->pci_dev) { - if (devpriv->s5933_config) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - - return 0; + status = inw(devpriv->control_status + ADCMUX_CONT); + if (status & EOC) + return 0; + return -EBUSY; } -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + struct cb_pcidas_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); unsigned int bits; - static const int timeout = 10000; - int channel; - /* enable calibration input if appropriate */ + int ret; + int n; + + /* enable calibration input if appropriate */ if (insn->chanspec & CR_ALT_SOURCE) { outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); - channel = 0; + chan = 0; } else { outw(0, devpriv->control_status + CALIBRATION_REG); - channel = CR_CHAN(insn->chanspec); } - /* set mux limits and gain */ - bits = BEGIN_SCAN(channel) | - END_SCAN(channel) | GAIN_BITS(CR_RANGE(insn->chanspec)); - /* set unipolar/bipolar */ - if (CR_RANGE(insn->chanspec) & IS_UNIPOLAR) + + /* set mux limits and gain */ + bits = BEGIN_SCAN(chan) | END_SCAN(chan) | GAIN_BITS(range); + /* set unipolar/bipolar */ + if (range & IS_UNIPOLAR) bits |= UNIP; - /* set singleended/differential */ - if (CR_AREF(insn->chanspec) != AREF_DIFF) + /* set single-ended/differential */ + if (aref != AREF_DIFF) bits |= SE; outw(bits, devpriv->control_status + ADCMUX_CONT); @@ -835,13 +430,9 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, outw(0, devpriv->adc_fifo + ADCDATA); /* wait for conversion to end */ - /* return -ETIMEDOUT if there is a timeout */ - for (i = 0; i < timeout; i++) { - if (inw(devpriv->control_status + ADCMUX_CONT) & EOC) - break; - } - if (i == timeout) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0); + if (ret) + return ret; /* read data */ data[n] = inw(devpriv->adc_fifo + ADCDATA); @@ -851,36 +442,28 @@ static int cb_pcidas_ai_rinsn(struct comedi_device *dev, return n; } -static int ai_config_calibration_source(struct comedi_device *dev, - unsigned int *data) -{ - static const int num_calibration_sources = 8; - unsigned int source = data[1]; - - if (source >= num_calibration_sources) { - printk("invalid calibration source: %i\n", source); - return -EINVAL; - } - - devpriv->calibration_source = source; - - return 2; -} - static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct cb_pcidas_private *devpriv = dev->private; int id = data[0]; + unsigned int source = data[1]; switch (id) { case INSN_CONFIG_ALT_SOURCE: - return ai_config_calibration_source(dev, data); + if (source >= 8) { + dev_err(dev->class_dev, + "invalid calibration source: %i\n", + source); + return -EINVAL; + } + devpriv->calibration_source = source; break; default: return -EINVAL; break; } - return -EINVAL; + return insn->n; } /* analog output insn for pcidas-1000 and 1200 series */ @@ -889,25 +472,26 @@ static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int channel; + struct cb_pcidas_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); unsigned long flags; - /* set channel and range */ - channel = CR_CHAN(insn->chanspec); + /* set channel and range */ spin_lock_irqsave(&dev->spinlock, flags); - devpriv->ao_control_bits &= - ~DAC_MODE_UPDATE_BOTH & ~DAC_RANGE_MASK(channel); - devpriv->ao_control_bits |= - DACEN | DAC_RANGE(channel, CR_RANGE(insn->chanspec)); + devpriv->ao_control_bits &= (~DAC_MODE_UPDATE_BOTH & + ~DAC_RANGE_MASK(chan)); + devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range)); outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); spin_unlock_irqrestore(&dev->spinlock, flags); - /* remember value for readback */ - devpriv->ao_value[channel] = data[0]; - /* send data */ - outw(data[0], devpriv->ao_registers + DAC_DATA_REG(channel)); + /* remember value for readback */ + devpriv->ao_value[chan] = data[0]; - return 1; + /* send data */ + outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan)); + + return insn->n; } /* analog output insn for pcidas-1602 series */ @@ -915,46 +499,84 @@ static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int channel; + struct cb_pcidas_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); unsigned long flags; - /* clear dac fifo */ + /* clear dac fifo */ outw(0, devpriv->ao_registers + DACFIFOCLR); - /* set channel and range */ - channel = CR_CHAN(insn->chanspec); + /* set channel and range */ spin_lock_irqsave(&dev->spinlock, flags); - devpriv->ao_control_bits &= - ~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) & ~DAC_RANGE_MASK(channel) & - ~DAC_PACER_MASK; - devpriv->ao_control_bits |= - DACEN | DAC_RANGE(channel, - CR_RANGE(insn-> - chanspec)) | DAC_CHAN_EN(channel) | - DAC_START; + devpriv->ao_control_bits &= (~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) & + ~DAC_RANGE_MASK(chan) & ~DAC_PACER_MASK); + devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range) | + DAC_CHAN_EN(chan) | DAC_START); outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); spin_unlock_irqrestore(&dev->spinlock, flags); - /* remember value for readback */ - devpriv->ao_value[channel] = data[0]; - /* send data */ + /* remember value for readback */ + devpriv->ao_value[chan] = data[0]; + + /* send data */ outw(data[0], devpriv->ao_registers + DACDATA); - return 1; + return insn->n; } -/* analog output readback insn */ -/* XXX loses track of analog output value back after an analog ouput command is executed */ 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; + unsigned int i; + + for (i = 0; i < timeout; i++) { + if ((inb(s5933_base_addr + + AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY) + == 0) + return 0; + udelay(1); + } + return -1; +} + +static int nvram_read(struct comedi_device *dev, unsigned int address, + uint8_t *data) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned long iobase = devpriv->s5933_config; + + if (wait_for_nvram_ready(iobase) < 0) + return -ETIMEDOUT; + + outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR, + iobase + AMCC_OP_REG_MCSR_NVCMD); + outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); + outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR, + iobase + AMCC_OP_REG_MCSR_NVCMD); + outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); + outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD); + + if (wait_for_nvram_ready(iobase) < 0) + return -ETIMEDOUT; + + *data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA); + + return 0; +} + static int eeprom_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -971,6 +593,56 @@ static int eeprom_read_insn(struct comedi_device *dev, return 1; } +static void write_calibration_bitstream(struct comedi_device *dev, + unsigned int register_bits, + unsigned int bitstream, + unsigned int bitstream_length) +{ + struct cb_pcidas_private *devpriv = dev->private; + static const int write_delay = 1; + unsigned int bit; + + for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { + if (bitstream & bit) + register_bits |= SERIAL_DATA_IN_BIT; + else + register_bits &= ~SERIAL_DATA_IN_BIT; + udelay(write_delay); + outw(register_bits, devpriv->control_status + CALIBRATION_REG); + } +} + +static int caldac_8800_write(struct comedi_device *dev, unsigned int address, + uint8_t value) +{ + struct cb_pcidas_private *devpriv = dev->private; + static const int num_caldac_channels = 8; + static const int bitstream_length = 11; + unsigned int bitstream = ((address & 0x7) << 8) | value; + static const int caldac_8800_udelay = 1; + + if (address >= num_caldac_channels) { + comedi_error(dev, "illegal caldac channel"); + return -1; + } + + if (value == devpriv->caldac_value[address]) + return 1; + + devpriv->caldac_value[address] = value; + + write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream, + bitstream_length); + + udelay(caldac_8800_udelay); + outw(cal_enable_bits(dev) | SELECT_8800_BIT, + devpriv->control_status + CALIBRATION_REG); + udelay(caldac_8800_udelay); + outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); + + return 1; +} + static int caldac_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -984,51 +656,112 @@ static int caldac_read_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->caldac_value[CR_CHAN(insn->chanspec)]; return 1; } /* 1602/16 pregain offset */ -static int dac08_write(struct comedi_device *dev, unsigned int value) +static void dac08_write(struct comedi_device *dev, unsigned int value) { - if (devpriv->dac08_value == value) - return 1; + struct cb_pcidas_private *devpriv = dev->private; + unsigned long cal_reg; - devpriv->dac08_value = value; + if (devpriv->dac08_value != value) { + devpriv->dac08_value = value; - outw(cal_enable_bits(dev) | (value & 0xff), - devpriv->control_status + CALIBRATION_REG); - udelay(1); - outw(cal_enable_bits(dev) | SELECT_DAC08_BIT | (value & 0xff), - devpriv->control_status + CALIBRATION_REG); - udelay(1); - outw(cal_enable_bits(dev) | (value & 0xff), - devpriv->control_status + CALIBRATION_REG); - udelay(1); + cal_reg = devpriv->control_status + CALIBRATION_REG; - return 1; + value &= 0xff; + value |= cal_enable_bits(dev); + + /* latch the new value into the caldac */ + outw(value, cal_reg); + udelay(1); + outw(value | SELECT_DAC08_BIT, cal_reg); + udelay(1); + outw(value, cal_reg); + udelay(1); + } } static int dac08_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - return dac08_write(dev, data[0]); + int i; + + for (i = 0; i < insn->n; i++) + dac08_write(dev, data[i]); + + return insn->n; } static int dac08_read_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->dac08_value; return 1; } +static int trimpot_7376_write(struct comedi_device *dev, uint8_t value) +{ + struct cb_pcidas_private *devpriv = dev->private; + static const int bitstream_length = 7; + unsigned int bitstream = value & 0x7f; + unsigned int register_bits; + static const int ad7376_udelay = 1; + + register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; + udelay(ad7376_udelay); + outw(register_bits, devpriv->control_status + CALIBRATION_REG); + + write_calibration_bitstream(dev, register_bits, bitstream, + bitstream_length); + + udelay(ad7376_udelay); + outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); + + return 0; +} + +/* For 1602/16 only + * ch 0 : adc gain + * ch 1 : adc postgain offset */ +static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, + uint8_t value) +{ + struct cb_pcidas_private *devpriv = dev->private; + static const int bitstream_length = 10; + unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); + unsigned int register_bits; + static const int ad8402_udelay = 1; + + register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; + udelay(ad8402_udelay); + outw(register_bits, devpriv->control_status + CALIBRATION_REG); + + write_calibration_bitstream(dev, register_bits, bitstream, + bitstream_length); + + udelay(ad8402_udelay); + outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); + + return 0; +} + 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); + struct cb_pcidas_private *devpriv = dev->private; + if (devpriv->trimpot_value[channel] == value) return 1; @@ -1062,6 +795,7 @@ static int trimpot_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct cb_pcidas_private *devpriv = dev->private; unsigned int channel = CR_CHAN(insn->chanspec); data[0] = devpriv->trimpot_value[channel]; @@ -1069,128 +803,108 @@ static int trimpot_read_insn(struct comedi_device *dev, return 1; } +static int cb_pcidas_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } + return 0; +} + static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct cb_pcidas_board *thisboard = comedi_board(dev); + struct cb_pcidas_private *devpriv = dev->private; int err = 0; - int tmp; - int i, gain, start_chan; - - /* 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. */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_NOW | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + unsigned int arg; + + /* 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_FOLLOW | TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_NOW | 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 2: make sure trigger sources are unique and mutually compatible */ - - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; - - /* make sure trigger sources are compatible with each other */ + /* 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->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) - err++; + err |= -EINVAL; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) - err++; + err |= -EINVAL; if (cmd->start_src == TRIG_EXT && (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)) - err++; + err |= -EINVAL; if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; case TRIG_EXT: /* External trigger, only CR_EDGE and CR_INVERT flags allowed */ if ((cmd->start_arg & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) { - cmd->start_arg &= - ~(CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT)); - err++; + cmd->start_arg &= ~(CR_FLAGS_MASK & + ~(CR_EDGE | CR_INVERT)); + err |= -EINVAL; } - if (!thisboard->has_ai_trig_invert && - (cmd->start_arg & CR_INVERT)) { + if (!thisboard->is_1602 && (cmd->start_arg & CR_INVERT)) { cmd->start_arg &= (CR_FLAGS_MASK & ~CR_INVERT); - err++; - } - break; - default: - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; + err |= -EINVAL; } break; } - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < - thisboard->ai_speed * cmd->chanlist_len) { - cmd->scan_begin_arg = - thisboard->ai_speed * cmd->chanlist_len; - err++; - } - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < thisboard->ai_speed) { - cmd->convert_arg = thisboard->ai_speed; - err++; - } - } + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + thisboard->ai_speed * cmd->chanlist_len); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_NONE) { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + thisboard->ai_speed); + + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_NONE) + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; @@ -1198,47 +912,28 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->scan_begin_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1246,9 +941,23 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, return 0; } +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; + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); +} + static int cb_pcidas_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct cb_pcidas_board *thisboard = comedi_board(dev); + struct cb_pcidas_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int bits; @@ -1278,17 +987,9 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, bits |= PACER_INT; outw(bits, devpriv->control_status + ADCMUX_CONT); -#ifdef CB_PCIDAS_DEBUG - printk("comedi: sent 0x%x to adcmux control\n", bits); -#endif - /* load counters */ - if (cmd->convert_src == TRIG_TIMER) - cb_pcidas_load_counters(dev, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - else if (cmd->scan_begin_src == TRIG_TIMER) - cb_pcidas_load_counters(dev, &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); + if (cmd->scan_begin_src == TRIG_TIMER || cmd->convert_src == TRIG_TIMER) + cb_pcidas_ai_load_counters(dev); /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) @@ -1298,16 +999,18 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, devpriv->adc_fifo_bits |= INTE; devpriv->adc_fifo_bits &= ~INT_MASK; if (cmd->flags & TRIG_WAKE_EOS) { - if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) - devpriv->adc_fifo_bits |= INT_EOS; /* interrupt end of burst */ - else - devpriv->adc_fifo_bits |= INT_FNE; /* interrupt fifo not empty */ + if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) { + /* interrupt end of burst */ + devpriv->adc_fifo_bits |= INT_EOS; + } else { + /* interrupt fifo not empty */ + devpriv->adc_fifo_bits |= INT_FNE; + } } else { - devpriv->adc_fifo_bits |= INT_FHF; /* interrupt fifo half full */ + /* interrupt fifo half full */ + devpriv->adc_fifo_bits |= INT_FHF; } -#ifdef CB_PCIDAS_DEBUG - printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits); -#endif + /* enable (and clear) interrupts */ outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL, devpriv->control_status + INT_ADCFIFO); @@ -1315,25 +1018,39 @@ static int cb_pcidas_ai_cmd(struct comedi_device *dev, /* set start trigger and burst mode */ bits = 0; - if (cmd->start_src == TRIG_NOW) + if (cmd->start_src == TRIG_NOW) { bits |= SW_TRIGGER; - else if (cmd->start_src == TRIG_EXT) { + } else { /* TRIG_EXT */ bits |= EXT_TRIGGER | TGEN | XTRCL; - if (thisboard->has_ai_trig_invert - && (cmd->start_arg & CR_INVERT)) - bits |= TGPOL; - if (thisboard->has_ai_trig_gated && (cmd->start_arg & CR_EDGE)) - bits |= TGSEL; - } else { - comedi_error(dev, "bug!"); - return -1; + if (thisboard->is_1602) { + if (cmd->start_arg & CR_INVERT) + bits |= TGPOL; + if (cmd->start_arg & CR_EDGE) + bits |= TGSEL; + } } if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) bits |= BURSTE; outw(bits, devpriv->control_status + TRIG_CONTSTAT); -#ifdef CB_PCIDAS_DEBUG - printk("comedi: sent 0x%x to trig control\n", bits); -#endif + + return 0; +} + +static int cb_pcidas_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + + if (cmd->chanlist_len > 1) { + unsigned int chan1 = CR_CHAN(cmd->chanlist[1]); + + if (chan0 != 0 || chan1 != 1) { + dev_dbg(dev->class_dev, + "channels must be ordered channel 0, channel 1 in chanlist\n"); + return -EINVAL; + } + } return 0; } @@ -1342,82 +1059,45 @@ 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); + struct cb_pcidas_private *devpriv = dev->private; int err = 0; - int tmp; - - /* 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. */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + unsigned int arg; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* 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->stop_src); - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < thisboard->ao_scan_speed) { - cmd->scan_begin_arg = thisboard->ao_scan_speed; - err++; - } - } + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + thisboard->ao_scan_speed); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_NONE) { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_NONE) + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; @@ -1425,28 +1105,20 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->ao_divisor1), - &(devpriv->ao_divisor2), - &(cmd->scan_begin_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->ao_divisor1, + &devpriv->ao_divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist && cmd->chanlist_len > 1) { - if (CR_CHAN(cmd->chanlist[0]) != 0 || - CR_CHAN(cmd->chanlist[1]) != 1) { - comedi_error(dev, - "channels must be ordered channel 0, channel 1 in chanlist\n"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1454,9 +1126,89 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, return 0; } +/* cancel analog input command */ +static int cb_pcidas_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned long flags; + + spin_lock_irqsave(&dev->spinlock, flags); + /* disable interrupts */ + devpriv->adc_fifo_bits &= ~INTE & ~EOAIE; + outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); + spin_unlock_irqrestore(&dev->spinlock, flags); + + /* disable start trigger source and burst mode */ + outw(0, devpriv->control_status + TRIG_CONTSTAT); + /* software pacer source */ + outw(0, devpriv->control_status + ADCMUX_CONT); + + return 0; +} + +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); + struct cb_pcidas_private *devpriv = dev->private; + unsigned int num_bytes, num_points = thisboard->fifo_size; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned long flags; + + if (trig_num != cmd->start_arg) + return -EINVAL; + + /* load up fifo */ + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points) + num_points = devpriv->ao_count; + + num_bytes = cfc_read_array_from_buffer(s, devpriv->ao_buffer, + num_points * sizeof(short)); + num_points = num_bytes / sizeof(short); + + if (cmd->stop_src == TRIG_COUNT) + devpriv->ao_count -= num_points; + /* write data to board's fifo */ + outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes); + + /* enable dac half-full and empty interrupts */ + spin_lock_irqsave(&dev->spinlock, flags); + devpriv->adc_fifo_bits |= DAEMIE | DAHFIE; + + /* enable and clear interrupts */ + outw(devpriv->adc_fifo_bits | DAEMI | DAHFI, + devpriv->control_status + INT_ADCFIFO); + + /* start dac */ + devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY; + outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); + + spin_unlock_irqrestore(&dev->spinlock, flags); + + async->inttrig = NULL; + + return 0; +} + +static void cb_pcidas_ao_load_counters(struct comedi_device *dev) +{ + struct cb_pcidas_private *devpriv = dev->private; + unsigned long timer_base = devpriv->pacer_counter_dio + DAC8254; + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->ao_divisor1); + i8254_write(timer_base, 0, 2, devpriv->ao_divisor2); +} + static int cb_pcidas_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct cb_pcidas_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int i; @@ -1482,19 +1234,9 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, outw(0, devpriv->ao_registers + DACFIFOCLR); /* load counters */ - if (cmd->scan_begin_src == TRIG_TIMER) { - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->ao_divisor1), - &(devpriv->ao_divisor2), - &(cmd->scan_begin_arg), - cmd->flags); - - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 1, - devpriv->ao_divisor1, 2); - i8254_load(devpriv->pacer_counter_dio + DAC8254, 0, 2, - devpriv->ao_divisor2, 2); - } + if (cmd->scan_begin_src == TRIG_TIMER) + cb_pcidas_ao_load_counters(dev); + /* set number of conversions */ if (cmd->stop_src == TRIG_COUNT) devpriv->ao_count = cmd->chanlist_len * cmd->stop_arg; @@ -1520,76 +1262,101 @@ static int cb_pcidas_ao_cmd(struct comedi_device *dev, return 0; } -static int cb_pcidas_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int trig_num) +/* cancel analog output command */ +static int cb_pcidas_ao_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - unsigned int num_bytes, num_points = thisboard->fifo_size; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &s->async->cmd; + struct cb_pcidas_private *devpriv = dev->private; unsigned long flags; - if (trig_num != 0) - return -EINVAL; + spin_lock_irqsave(&dev->spinlock, flags); + /* disable interrupts */ + devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE; + outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); - /* load up fifo */ - if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count < num_points) - num_points = devpriv->ao_count; + /* disable output */ + devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK; + outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); + spin_unlock_irqrestore(&dev->spinlock, flags); - num_bytes = cfc_read_array_from_buffer(s, devpriv->ao_buffer, - num_points * sizeof(short)); - num_points = num_bytes / sizeof(short); + return 0; +} - if (cmd->stop_src == TRIG_COUNT) - devpriv->ao_count -= num_points; - /* write data to board's fifo */ - outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, num_bytes); +static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) +{ + const struct cb_pcidas_board *thisboard = comedi_board(dev); + struct cb_pcidas_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->write_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int half_fifo = thisboard->fifo_size / 2; + unsigned int num_points; + unsigned long flags; - /* enable dac half-full and empty interrupts */ - spin_lock_irqsave(&dev->spinlock, flags); - devpriv->adc_fifo_bits |= DAEMIE | DAHFIE; -#ifdef CB_PCIDAS_DEBUG - printk("comedi: adc_fifo_bits are 0x%x\n", devpriv->adc_fifo_bits); -#endif - /* enable and clear interrupts */ - outw(devpriv->adc_fifo_bits | DAEMI | DAHFI, - devpriv->control_status + INT_ADCFIFO); + if (status & DAEMI) { + /* clear dac empty interrupt latch */ + spin_lock_irqsave(&dev->spinlock, flags); + outw(devpriv->adc_fifo_bits | DAEMI, + devpriv->control_status + INT_ADCFIFO); + spin_unlock_irqrestore(&dev->spinlock, flags); + if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) { + if (cmd->stop_src == TRIG_NONE || + (cmd->stop_src == TRIG_COUNT + && devpriv->ao_count)) { + comedi_error(dev, "dac fifo underflow"); + async->events |= COMEDI_CB_ERROR; + } + async->events |= COMEDI_CB_EOA; + } + } else if (status & DAHFI) { + unsigned int num_bytes; - /* start dac */ - devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY; - outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); -#ifdef CB_PCIDAS_DEBUG - printk("comedi: sent 0x%x to dac control\n", devpriv->ao_control_bits); -#endif - spin_unlock_irqrestore(&dev->spinlock, flags); + /* figure out how many points we are writing to fifo */ + num_points = half_fifo; + if (cmd->stop_src == TRIG_COUNT && + devpriv->ao_count < num_points) + num_points = devpriv->ao_count; + num_bytes = + cfc_read_array_from_buffer(s, devpriv->ao_buffer, + num_points * sizeof(short)); + num_points = num_bytes / sizeof(short); - async->inttrig = NULL; + if (cmd->stop_src == TRIG_COUNT) + devpriv->ao_count -= num_points; + /* write data to board's fifo */ + outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, + num_points); + /* clear half-full interrupt latch */ + spin_lock_irqsave(&dev->spinlock, flags); + outw(devpriv->adc_fifo_bits | DAHFI, + devpriv->control_status + INT_ADCFIFO); + spin_unlock_irqrestore(&dev->spinlock, flags); + } - return 0; + cfc_handle_events(dev, s); } 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); + struct cb_pcidas_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async; + struct comedi_cmd *cmd; int status, s5933_status; int half_fifo = thisboard->fifo_size / 2; unsigned int num_samples, i; static const int timeout = 10000; unsigned long flags; - if (dev->attached == 0) + if (!dev->attached) return IRQ_NONE; async = s->async; - async->events = 0; + cmd = &async->cmd; s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR); -#ifdef CB_PCIDAS_DEBUG - printk("intcsr 0x%x\n", s5933_status); - printk("mbef 0x%x\n", inl(devpriv->s5933_config + AMCC_OP_REG_MBEF)); -#endif if ((INTCSR_INTR_ASSERTED & s5933_status) == 0) return IRQ_NONE; @@ -1601,10 +1368,6 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) devpriv->s5933_config + AMCC_OP_REG_INTCSR); status = inw(devpriv->control_status + INT_ADCFIFO); -#ifdef CB_PCIDAS_DEBUG - if ((status & (INT | EOAI | LADFUL | DAHFI | DAEMI)) == 0) - comedi_error(dev, "spurious interrupt"); -#endif /* check for analog output interrupt */ if (status & (DAHFI | DAEMI)) @@ -1614,7 +1377,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) if (status & ADHFI) { /* read data */ num_samples = half_fifo; - if (async->cmd.stop_src == TRIG_COUNT && + if (cmd->stop_src == TRIG_COUNT && num_samples > devpriv->count) { num_samples = devpriv->count; } @@ -1623,10 +1386,8 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) cfc_write_array_to_buffer(s, devpriv->ai_buffer, num_samples * sizeof(short)); devpriv->count -= num_samples; - if (async->cmd.stop_src == TRIG_COUNT && devpriv->count == 0) { + if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) async->events |= COMEDI_CB_EOA; - cb_pcidas_cancel(dev, s); - } /* clear half-full interrupt latch */ spin_lock_irqsave(&dev->spinlock, flags); outw(devpriv->adc_fifo_bits | INT, @@ -1640,8 +1401,9 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) INT_ADCFIFO)) == 0) break; cfc_write_to_buffer(s, inw(devpriv->adc_fifo)); - if (async->cmd.stop_src == TRIG_COUNT && --devpriv->count == 0) { /* end of acquisition */ - cb_pcidas_cancel(dev, s); + if (cmd->stop_src == TRIG_COUNT && + --devpriv->count == 0) { + /* end of acquisition */ async->events |= COMEDI_CB_EOA; break; } @@ -1668,295 +1430,222 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) outw(devpriv->adc_fifo_bits | LADFUL, devpriv->control_status + INT_ADCFIFO); spin_unlock_irqrestore(&dev->spinlock, flags); - cb_pcidas_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } -static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status) +static int cb_pcidas_auto_attach(struct comedi_device *dev, + unsigned long context) { - struct comedi_subdevice *s = dev->write_subdev; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; - unsigned int half_fifo = thisboard->fifo_size / 2; - unsigned int num_points; - unsigned long flags; - - async->events = 0; - - if (status & DAEMI) { - /* clear dac empty interrupt latch */ - spin_lock_irqsave(&dev->spinlock, flags); - outw(devpriv->adc_fifo_bits | DAEMI, - devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); - if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) { - if (cmd->stop_src == TRIG_NONE || - (cmd->stop_src == TRIG_COUNT - && devpriv->ao_count)) { - comedi_error(dev, "dac fifo underflow"); - cb_pcidas_ao_cancel(dev, s); - async->events |= COMEDI_CB_ERROR; - } - async->events |= COMEDI_CB_EOA; - } - } else if (status & DAHFI) { - unsigned int num_bytes; - - /* figure out how many points we are writing to fifo */ - num_points = half_fifo; - if (cmd->stop_src == TRIG_COUNT && - devpriv->ao_count < num_points) - num_points = devpriv->ao_count; - num_bytes = - cfc_read_array_from_buffer(s, devpriv->ao_buffer, - num_points * sizeof(short)); - num_points = num_bytes / sizeof(short); - - if (async->cmd.stop_src == TRIG_COUNT) - devpriv->ao_count -= num_points; - /* write data to board's fifo */ - outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, - num_points); - /* clear half-full interrupt latch */ - spin_lock_irqsave(&dev->spinlock, flags); - outw(devpriv->adc_fifo_bits | DAHFI, - devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); - } - - comedi_event(dev, s); -} - -/* cancel analog input command */ -static int cb_pcidas_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->spinlock, flags); - /* disable interrupts */ - devpriv->adc_fifo_bits &= ~INTE & ~EOAIE; - outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* disable start trigger source and burst mode */ - outw(0, devpriv->control_status + TRIG_CONTSTAT); - /* software pacer source */ - outw(0, devpriv->control_status + ADCMUX_CONT); - - return 0; -} - -/* cancel analog output command */ -static int cb_pcidas_ao_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->spinlock, flags); - /* disable interrupts */ - devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE; - outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO); - - /* disable output */ - devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK; - outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR); - spin_unlock_irqrestore(&dev->spinlock, flags); + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct cb_pcidas_board *thisboard = NULL; + struct cb_pcidas_private *devpriv; + struct comedi_subdevice *s; + int i; + int ret; - return 0; -} + if (context < ARRAY_SIZE(cb_pcidas_boards)) + thisboard = &cb_pcidas_boards[context]; + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; -static void cb_pcidas_load_counters(struct comedi_device *dev, unsigned int *ns, - int rounding_flags) -{ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), - &(devpriv->divisor2), ns, - rounding_flags & TRIG_ROUND_MASK); - - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 1, - devpriv->divisor1, 2); - i8254_load(devpriv->pacer_counter_dio + ADC8254, 0, 2, - devpriv->divisor2, 2); -} + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; -static void write_calibration_bitstream(struct comedi_device *dev, - unsigned int register_bits, - unsigned int bitstream, - unsigned int bitstream_length) -{ - static const int write_delay = 1; - unsigned int bit; + ret = comedi_pci_enable(dev); + if (ret) + return ret; - for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { - if (bitstream & bit) - register_bits |= SERIAL_DATA_IN_BIT; - else - register_bits &= ~SERIAL_DATA_IN_BIT; - udelay(write_delay); - outw(register_bits, devpriv->control_status + CALIBRATION_REG); - } -} + 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); + if (thisboard->ao_nchan) + devpriv->ao_registers = pci_resource_start(pcidev, 4); -static int caldac_8800_write(struct comedi_device *dev, unsigned int address, - uint8_t value) -{ - static const int num_caldac_channels = 8; - static const int bitstream_length = 11; - unsigned int bitstream = ((address & 0x7) << 8) | value; - static const int caldac_8800_udelay = 1; + /* disable and clear interrupts on amcc s5933 */ + outl(INTCSR_INBOX_INTR_STATUS, + devpriv->s5933_config + AMCC_OP_REG_INTCSR); - if (address >= num_caldac_channels) { - comedi_error(dev, "illegal caldac channel"); - return -1; + if (request_irq(pcidev->irq, cb_pcidas_interrupt, + IRQF_SHARED, dev->driver->driver_name, dev)) { + dev_dbg(dev->class_dev, "unable to allocate irq %d\n", + pcidev->irq); + return -EINVAL; } + dev->irq = pcidev->irq; - if (value == devpriv->caldac_value[address]) - return 1; + ret = comedi_alloc_subdevices(dev, 7); + if (ret) + return ret; - devpriv->caldac_value[address] = value; - - write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream, - bitstream_length); - - udelay(caldac_8800_udelay); - outw(cal_enable_bits(dev) | SELECT_8800_BIT, - devpriv->control_status + CALIBRATION_REG); - udelay(caldac_8800_udelay); - outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); - - return 1; -} - -static int trimpot_7376_write(struct comedi_device *dev, uint8_t value) -{ - static const int bitstream_length = 7; - unsigned int bitstream = value & 0x7f; - unsigned int register_bits; - static const int ad7376_udelay = 1; - - register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; - udelay(ad7376_udelay); - outw(register_bits, devpriv->control_status + CALIBRATION_REG); - - write_calibration_bitstream(dev, register_bits, bitstream, - bitstream_length); - - udelay(ad7376_udelay); - outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); - - return 0; -} - -/* For 1602/16 only - * ch 0 : adc gain - * ch 1 : adc postgain offset */ -static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel, - uint8_t value) -{ - static const int bitstream_length = 10; - unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); - unsigned int register_bits; - static const int ad8402_udelay = 1; - - register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT; - udelay(ad8402_udelay); - outw(register_bits, devpriv->control_status + CALIBRATION_REG); + s = &dev->subdevices[0]; + /* analog input subdevice */ + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; + /* WARNING: Number of inputs in differential mode is ignored */ + s->n_chan = thisboard->ai_nchan; + s->len_chanlist = thisboard->ai_nchan; + s->maxdata = (1 << thisboard->ai_bits) - 1; + s->range_table = thisboard->ranges; + s->insn_read = cb_pcidas_ai_rinsn; + s->insn_config = ai_config_insn; + s->do_cmd = cb_pcidas_ai_cmd; + s->do_cmdtest = cb_pcidas_ai_cmdtest; + s->cancel = cb_pcidas_cancel; - write_calibration_bitstream(dev, register_bits, bitstream, - bitstream_length); + /* analog output subdevice */ + s = &dev->subdevices[1]; + if (thisboard->ao_nchan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; + s->n_chan = thisboard->ao_nchan; + /* + * analog out resolution is the same as + * analog input resolution, so use ai_bits + */ + s->maxdata = (1 << thisboard->ai_bits) - 1; + s->range_table = &cb_pcidas_ao_ranges; + s->insn_read = cb_pcidas_ao_readback_insn; + if (thisboard->has_ao_fifo) { + dev->write_subdev = s; + s->subdev_flags |= SDF_CMD_WRITE; + 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; + } - udelay(ad8402_udelay); - outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG); + /* 8255 */ + s = &dev->subdevices[2]; + ret = subdev_8255_init(dev, s, NULL, + devpriv->pacer_counter_dio + DIO_8255); + if (ret) + return ret; - return 0; -} + /* serial EEPROM, */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE | SDF_INTERNAL; + s->n_chan = 256; + s->maxdata = 0xff; + s->insn_read = eeprom_read_insn; -static int wait_for_nvram_ready(unsigned long s5933_base_addr) -{ - static const int timeout = 1000; - unsigned int i; + /* 8800 caldac */ + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = NUM_CHANNELS_8800; + s->maxdata = 0xff; + s->insn_read = caldac_read_insn; + s->insn_write = caldac_write_insn; + for (i = 0; i < s->n_chan; i++) + caldac_8800_write(dev, i, s->maxdata / 2); - for (i = 0; i < timeout; i++) { - if ((inb(s5933_base_addr + - AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY) - == 0) - return 0; - udelay(1); + /* trim potentiometer */ + s = &dev->subdevices[5]; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + if (thisboard->trimpot == AD7376) { + s->n_chan = NUM_CHANNELS_7376; + s->maxdata = 0x7f; + } else { + s->n_chan = NUM_CHANNELS_8402; + s->maxdata = 0xff; } - return -1; -} - -static int nvram_read(struct comedi_device *dev, unsigned int address, - uint8_t *data) -{ - unsigned long iobase = devpriv->s5933_config; - - if (wait_for_nvram_ready(iobase) < 0) - return -ETIMEDOUT; - - outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR, - iobase + AMCC_OP_REG_MCSR_NVCMD); - outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); - outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR, - iobase + AMCC_OP_REG_MCSR_NVCMD); - outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA); - outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD); + s->insn_read = trimpot_read_insn; + s->insn_write = trimpot_write_insn; + for (i = 0; i < s->n_chan; i++) + cb_pcidas_trimpot_write(dev, i, s->maxdata / 2); - if (wait_for_nvram_ready(iobase) < 0) - return -ETIMEDOUT; + /* dac08 caldac */ + s = &dev->subdevices[6]; + if (thisboard->has_dac08) { + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = NUM_CHANNELS_DAC08; + s->insn_read = dac08_read_insn; + s->insn_write = dac08_write_insn; + s->maxdata = 0xff; + dac08_write(dev, s->maxdata / 2); + } else + s->type = COMEDI_SUBD_UNUSED; - *data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA); + /* make sure mailbox 4 is empty */ + inl(devpriv->s5933_config + AMCC_OP_REG_IMB4); + /* Set bits to enable incoming mailbox interrupts on amcc s5933. */ + devpriv->s5933_intcsr_bits = + INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) | + INTCSR_INBOX_FULL_INT; + /* clear and enable interrupt on amcc s5933 */ + outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, + devpriv->s5933_config + AMCC_OP_REG_INTCSR); return 0; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static void cb_pcidas_detach(struct comedi_device *dev) { - return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name); -} + struct cb_pcidas_private *devpriv = dev->private; -static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); + if (devpriv) { + if (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); } -static struct pci_driver driver_cb_pcidas_pci_driver = { - .id_table = cb_pcidas_pci_table, - .probe = &driver_cb_pcidas_pci_probe, - .remove = __devexit_p(&driver_cb_pcidas_pci_remove) +static struct comedi_driver cb_pcidas_driver = { + .driver_name = "cb_pcidas", + .module = THIS_MODULE, + .auto_attach = cb_pcidas_auto_attach, + .detach = cb_pcidas_detach, }; -static int __init driver_cb_pcidas_init_module(void) +static int cb_pcidas_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_cb_pcidas); - if (retval < 0) - return retval; - - driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name; - return pci_register_driver(&driver_cb_pcidas_pci_driver); + return comedi_pci_auto_config(dev, &cb_pcidas_driver, + id->driver_data); } -static void __exit driver_cb_pcidas_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcidas_pci_driver); - comedi_driver_unregister(&driver_cb_pcidas); -} +static const struct pci_device_id cb_pcidas_pci_table[] = { + { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 }, + { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 }, + { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 }, + { PCI_VDEVICE(CB, 0x0019), BOARD_PCIDAS1200_JR }, + { PCI_VDEVICE(CB, 0x001c), BOARD_PCIDAS1602_16_JR }, + { PCI_VDEVICE(CB, 0x004c), BOARD_PCIDAS1000 }, + { PCI_VDEVICE(CB, 0x001a), BOARD_PCIDAS1001 }, + { PCI_VDEVICE(CB, 0x001b), BOARD_PCIDAS1002 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table); -module_init(driver_cb_pcidas_init_module); -module_exit(driver_cb_pcidas_cleanup_module); +static struct pci_driver cb_pcidas_pci_driver = { + .name = "cb_pcidas", + .id_table = cb_pcidas_pci_table, + .probe = cb_pcidas_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 1e324198996..035c3a17600 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -28,100 +28,84 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ +*/ /* - -Driver: cb_pcidas64 -Description: MeasurementComputing PCI-DAS64xx, 60XX, and 4020 series with the PLX 9080 PCI controller -Author: Frank Mori Hess <fmhess@users.sourceforge.net> -Status: works -Updated: 2002-10-09 -Devices: [Measurement Computing] PCI-DAS6402/16 (cb_pcidas64), - PCI-DAS6402/12, PCI-DAS64/M1/16, PCI-DAS64/M2/16, - PCI-DAS64/M3/16, PCI-DAS6402/16/JR, PCI-DAS64/M1/16/JR, - PCI-DAS64/M2/16/JR, PCI-DAS64/M3/16/JR, PCI-DAS64/M1/14, - PCI-DAS64/M2/14, PCI-DAS64/M3/14, PCI-DAS6013, PCI-DAS6014, - PCI-DAS6023, PCI-DAS6025, PCI-DAS6030, - PCI-DAS6031, PCI-DAS6032, PCI-DAS6033, PCI-DAS6034, - PCI-DAS6035, PCI-DAS6036, PCI-DAS6040, PCI-DAS6052, - PCI-DAS6070, PCI-DAS6071, PCI-DAS4020/12 - -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - -These boards may be autocalibrated with the comedi_calibrate utility. - -To select the bnc trigger input on the 4020 (instead of the dio input), -specify a nonzero channel in the chanspec. If you wish to use an external -master clock on the 4020, you may do so by setting the scan_begin_src -to TRIG_OTHER, and using an INSN_CONFIG_TIMER_1 configuration insn -to configure the divisor to use for the external clock. - -Some devices are not identified because the PCI device IDs are not yet -known. If you have such a board, please file a bug report at -https://bugs.comedi.org. - -*/ + * Driver: cb_pcidas64 + * Description: MeasurementComputing PCI-DAS64xx, 60XX, and 4020 series + * with the PLX 9080 PCI controller + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Status: works + * Updated: Fri, 02 Nov 2012 18:58:55 +0000 + * Devices: [Measurement Computing] PCI-DAS6402/16 (cb_pcidas64), + * PCI-DAS6402/12, PCI-DAS64/M1/16, PCI-DAS64/M2/16, + * PCI-DAS64/M3/16, PCI-DAS6402/16/JR, PCI-DAS64/M1/16/JR, + * PCI-DAS64/M2/16/JR, PCI-DAS64/M3/16/JR, PCI-DAS64/M1/14, + * PCI-DAS64/M2/14, PCI-DAS64/M3/14, PCI-DAS6013, PCI-DAS6014, + * PCI-DAS6023, PCI-DAS6025, PCI-DAS6030, + * PCI-DAS6031, PCI-DAS6032, PCI-DAS6033, PCI-DAS6034, + * PCI-DAS6035, PCI-DAS6036, PCI-DAS6040, PCI-DAS6052, + * PCI-DAS6070, PCI-DAS6071, PCI-DAS4020/12 + * + * Configuration options: + * None. + * + * Manual attachment of PCI cards with the comedi_config utility is not + * supported by this driver; they are attached automatically. + * + * These boards may be autocalibrated with the comedi_calibrate utility. + * + * To select the bnc trigger input on the 4020 (instead of the dio input), + * specify a nonzero channel in the chanspec. If you wish to use an external + * master clock on the 4020, you may do so by setting the scan_begin_src + * to TRIG_OTHER, and using an INSN_CONFIG_TIMER_1 configuration insn + * to configure the divisor to use for the external clock. + * + * Some devices are not identified because the PCI device IDs are not yet + * known. If you have such a board, please let the maintainers know. + */ /* TODO: make it return error if user attempts an ai command that uses the - external queue, and an ao command simultaneously - user counter subdevice + external queue, and an ao command simultaneously user counter subdevice there are a number of boards this driver will support when they are - fully released, but does not yet since the pci device id numbers - are not yet available. - support prescaled 100khz clock for slow pacing (not available on 6000 series?) + fully released, but does not yet since the pci device id numbers + are not yet available. + + support prescaled 100khz clock for slow pacing (not available on 6000 + series?) + make ao fifo size adjustable like ai fifo */ -#include "../comedidev.h" +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include <asm/system.h> -#include "comedi_pci.h" +#include "../comedidev.h" + #include "8253.h" #include "8255.h" #include "plx9080.h" #include "comedi_fc.h" -#undef PCIDAS64_DEBUG /* disable debugging code */ -/* #define PCIDAS64_DEBUG enable debugging code */ - -#ifdef PCIDAS64_DEBUG -#define DEBUG_PRINT(format, args...) printk(format , ## args) -#else -#define DEBUG_PRINT(format, args...) -#endif - #define TIMER_BASE 25 /* 40MHz master clock */ -#define PRESCALED_TIMER_BASE 10000 /* 100kHz 'prescaled' clock for slow acquisition, maybe I'll support this someday */ +/* 100kHz 'prescaled' clock for slow acquisition, + * maybe I'll support this someday */ +#define PRESCALED_TIMER_BASE 10000 #define DMA_BUFFER_SIZE 0x1000 -#define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307 - /* maximum value that can be loaded into board's 24-bit counters*/ static const int max_counter_value = 0xffffff; /* PCI-DAS64xxx base addresses */ -/* indices of base address regions */ -enum base_address_regions { - PLX9080_BADDRINDEX = 0, - MAIN_BADDRINDEX = 2, - DIO_COUNTER_BADDRINDEX = 3, -}; - -/* priv(dev)->main_iobase registers */ +/* devpriv->main_iobase registers */ enum write_only_registers { INTR_ENABLE_REG = 0x0, /* interrupt enable register */ HW_CONFIG_REG = 0x2, /* hardware config register */ @@ -130,26 +114,36 @@ enum write_only_registers { ADC_CONTROL0_REG = 0x10, /* adc control register 0 */ ADC_CONTROL1_REG = 0x12, /* adc control register 1 */ CALIBRATION_REG = 0x14, - ADC_SAMPLE_INTERVAL_LOWER_REG = 0x16, /* lower 16 bits of adc sample interval counter */ - ADC_SAMPLE_INTERVAL_UPPER_REG = 0x18, /* upper 8 bits of adc sample interval counter */ - ADC_DELAY_INTERVAL_LOWER_REG = 0x1a, /* lower 16 bits of delay interval counter */ - ADC_DELAY_INTERVAL_UPPER_REG = 0x1c, /* upper 8 bits of delay interval counter */ - ADC_COUNT_LOWER_REG = 0x1e, /* lower 16 bits of hardware conversion/scan counter */ - ADC_COUNT_UPPER_REG = 0x20, /* upper 8 bits of hardware conversion/scan counter */ + /* lower 16 bits of adc sample interval counter */ + ADC_SAMPLE_INTERVAL_LOWER_REG = 0x16, + /* upper 8 bits of adc sample interval counter */ + ADC_SAMPLE_INTERVAL_UPPER_REG = 0x18, + /* lower 16 bits of delay interval counter */ + ADC_DELAY_INTERVAL_LOWER_REG = 0x1a, + /* upper 8 bits of delay interval counter */ + ADC_DELAY_INTERVAL_UPPER_REG = 0x1c, + /* lower 16 bits of hardware conversion/scan counter */ + ADC_COUNT_LOWER_REG = 0x1e, + /* upper 8 bits of hardware conversion/scan counter */ + ADC_COUNT_UPPER_REG = 0x20, ADC_START_REG = 0x22, /* software trigger to start acquisition */ ADC_CONVERT_REG = 0x24, /* initiates single conversion */ ADC_QUEUE_CLEAR_REG = 0x26, /* clears adc queue */ ADC_QUEUE_LOAD_REG = 0x28, /* loads adc queue */ ADC_BUFFER_CLEAR_REG = 0x2a, - ADC_QUEUE_HIGH_REG = 0x2c, /* high channel for internal queue, use adc_chan_bits() inline above */ + /* high channel for internal queue, use adc_chan_bits() inline above */ + ADC_QUEUE_HIGH_REG = 0x2c, DAC_CONTROL0_REG = 0x50, /* dac control register 0 */ DAC_CONTROL1_REG = 0x52, /* dac control register 0 */ - DAC_SAMPLE_INTERVAL_LOWER_REG = 0x54, /* lower 16 bits of dac sample interval counter */ - DAC_SAMPLE_INTERVAL_UPPER_REG = 0x56, /* upper 8 bits of dac sample interval counter */ + /* lower 16 bits of dac sample interval counter */ + DAC_SAMPLE_INTERVAL_LOWER_REG = 0x54, + /* upper 8 bits of dac sample interval counter */ + DAC_SAMPLE_INTERVAL_UPPER_REG = 0x56, DAC_SELECT_REG = 0x60, DAC_START_REG = 0x64, DAC_BUFFER_CLEAR_REG = 0x66, /* clear dac buffer */ }; + static inline unsigned int dac_convert_reg(unsigned int channel) { return 0x70 + (2 * (channel & 0x1)); @@ -166,7 +160,9 @@ static inline unsigned int dac_msb_4020_reg(unsigned int channel) } enum read_only_registers { - HW_STATUS_REG = 0x0, /* hardware status register, reading this apparently clears pending interrupts as well */ + /* hardware status register, + * reading this apparently clears pending interrupts as well */ + HW_STATUS_REG = 0x0, PIPE1_READ_REG = 0x4, ADC_READ_PNTR_REG = 0x8, LOWER_XFER_REG = 0x10, @@ -176,12 +172,14 @@ enum read_only_registers { enum read_write_registers { I8255_4020_REG = 0x48, /* 8255 offset, for 4020 only */ - ADC_QUEUE_FIFO_REG = 0x100, /* external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG */ + /* external channel/gain queue, uses same bits as ADC_QUEUE_LOAD_REG */ + ADC_QUEUE_FIFO_REG = 0x100, ADC_FIFO_REG = 0x200, /* adc data fifo */ - DAC_FIFO_REG = 0x300, /* dac data fifo, has weird interactions with external channel queue */ + /* dac data fifo, has weird interactions with external channel queue */ + DAC_FIFO_REG = 0x300, }; -/* priv(dev)->dio_counter_iobase registers */ +/* devpriv->dio_counter_iobase registers */ enum dio_counter_registers { DIO_8255_OFFSET = 0x0, DO_REG = 0x20, @@ -193,13 +191,13 @@ enum dio_counter_registers { /* bit definitions for write-only registers */ enum intr_enable_contents { - ADC_INTR_SRC_MASK = 0x3, /* bits that set adc interrupt source */ - ADC_INTR_QFULL_BITS = 0x0, /* interrupt fifo quater full */ + ADC_INTR_SRC_MASK = 0x3, /* adc interrupt source mask */ + ADC_INTR_QFULL_BITS = 0x0, /* interrupt fifo quarter full */ ADC_INTR_EOC_BITS = 0x1, /* interrupt end of conversion */ ADC_INTR_EOSCAN_BITS = 0x2, /* interrupt end of scan */ - ADC_INTR_EOSEQ_BITS = 0x3, /* interrupt end of sequence (probably wont use this it's pretty fancy) */ + ADC_INTR_EOSEQ_BITS = 0x3, /* interrupt end of sequence mask */ EN_ADC_INTR_SRC_BIT = 0x4, /* enable adc interrupt source */ - EN_ADC_DONE_INTR_BIT = 0x8, /* enable adc acquisition done interrupt */ + EN_ADC_DONE_INTR_BIT = 0x8, /* enable adc acquisition done intr */ DAC_INTR_SRC_MASK = 0x30, DAC_INTR_QEMPTY_BITS = 0x0, DAC_INTR_HIGH_CHAN_BITS = 0x10, @@ -213,25 +211,33 @@ enum intr_enable_contents { }; enum hw_config_contents { - MASTER_CLOCK_4020_MASK = 0x3, /* bits that specify master clock source for 4020 */ - INTERNAL_CLOCK_4020_BITS = 0x1, /* use 40 MHz internal master clock for 4020 */ + MASTER_CLOCK_4020_MASK = 0x3, /* master clock source mask for 4020 */ + INTERNAL_CLOCK_4020_BITS = 0x1, /* use 40 MHz internal master clock */ BNC_CLOCK_4020_BITS = 0x2, /* use BNC input for master clock */ EXT_CLOCK_4020_BITS = 0x3, /* use dio input for master clock */ - EXT_QUEUE_BIT = 0x200, /* use external channel/gain queue (more versatile than internal queue) */ - SLOW_DAC_BIT = 0x400, /* use 225 nanosec strobe when loading dac instead of 50 nanosec */ - HW_CONFIG_DUMMY_BITS = 0x2000, /* bit with unknown function yet given as default value in pci-das64 manual */ - DMA_CH_SELECT_BIT = 0x8000, /* bit selects channels 1/0 for analog input/output, otherwise 0/1 */ - FIFO_SIZE_REG = 0x4, /* allows adjustment of fifo sizes */ + EXT_QUEUE_BIT = 0x200, /* use external channel/gain queue */ + /* use 225 nanosec strobe when loading dac instead of 50 nanosec */ + SLOW_DAC_BIT = 0x400, + /* bit with unknown function yet given as default value in pci-das64 + * manual */ + HW_CONFIG_DUMMY_BITS = 0x2000, + /* bit selects channels 1/0 for analog input/output, otherwise 0/1 */ + DMA_CH_SELECT_BIT = 0x8000, + FIFO_SIZE_REG = 0x4, /* allows adjustment of fifo sizes */ DAC_FIFO_SIZE_MASK = 0xff00, /* bits that set dac fifo size */ - DAC_FIFO_BITS = 0xf800, /* 8k sample ao fifo */ + DAC_FIFO_BITS = 0xf800, /* 8k sample ao fifo */ }; #define DAC_FIFO_SIZE 0x2000 enum daq_atrig_low_4020_contents { - EXT_AGATE_BNC_BIT = 0x8000, /* use trig/ext clk bnc input for analog gate signal */ - EXT_STOP_TRIG_BNC_BIT = 0x4000, /* use trig/ext clk bnc input for external stop trigger signal */ - EXT_START_TRIG_BNC_BIT = 0x2000, /* use trig/ext clk bnc input for external start trigger signal */ + /* use trig/ext clk bnc input for analog gate signal */ + EXT_AGATE_BNC_BIT = 0x8000, + /* use trig/ext clk bnc input for external stop trigger signal */ + EXT_STOP_TRIG_BNC_BIT = 0x4000, + /* use trig/ext clk bnc input for external start trigger signal */ + EXT_START_TRIG_BNC_BIT = 0x2000, }; + static inline uint16_t analog_trig_low_threshold_bits(uint16_t threshold) { return threshold & 0xfff; @@ -249,14 +255,17 @@ enum adc_control0_contents { ADC_START_TRIG_ANALOG_BITS = 0x30, ADC_START_TRIG_MASK = 0x30, ADC_START_TRIG_FALLING_BIT = 0x40, /* trig 1 uses falling edge */ - ADC_EXT_CONV_FALLING_BIT = 0x800, /* external pacing uses falling edge */ - ADC_SAMPLE_COUNTER_EN_BIT = 0x1000, /* enable hardware scan counter */ + /* external pacing uses falling edge */ + ADC_EXT_CONV_FALLING_BIT = 0x800, + /* enable hardware scan counter */ + ADC_SAMPLE_COUNTER_EN_BIT = 0x1000, ADC_DMA_DISABLE_BIT = 0x4000, /* disables dma */ ADC_ENABLE_BIT = 0x8000, /* master adc enable */ }; enum adc_control1_contents { - ADC_QUEUE_CONFIG_BIT = 0x1, /* should be set for boards with > 16 channels */ + /* should be set for boards with > 16 channels */ + ADC_QUEUE_CONFIG_BIT = 0x1, CONVERT_POLARITY_BIT = 0x10, EOC_POLARITY_BIT = 0x20, ADC_SW_GATE_BIT = 0x40, /* software gate of adc */ @@ -265,10 +274,11 @@ enum adc_control1_contents { ADC_LO_CHANNEL_4020_MASK = 0x300, ADC_HI_CHANNEL_4020_MASK = 0xc00, TWO_CHANNEL_4020_BITS = 0x1000, /* two channel mode for 4020 */ - FOUR_CHANNEL_4020_BITS = 0x2000, /* four channel mode for 4020 */ + FOUR_CHANNEL_4020_BITS = 0x2000, /* four channel mode for 4020 */ CHANNEL_MODE_4020_MASK = 0x3000, ADC_MODE_MASK = 0xf000, }; + static inline uint16_t adc_lo_chan_4020_bits(unsigned int channel) { return (channel & 0x3) << 8; @@ -291,9 +301,10 @@ enum calibration_contents { CAL_EN_64XX_BIT = 0x40, /* calibration enable for 64xx series */ SERIAL_DATA_IN_BIT = 0x80, SERIAL_CLOCK_BIT = 0x100, - CAL_EN_60XX_BIT = 0x200, /* calibration enable for 60xx series */ + CAL_EN_60XX_BIT = 0x200, /* calibration enable for 60xx series */ CAL_GAIN_BIT = 0x800, }; + /* calibration sources for 6025 are: * 0 : ground * 1 : 10V @@ -304,6 +315,7 @@ enum calibration_contents { * 6 : dac channel 0 * 7 : dac channel 1 */ + static inline uint16_t adc_src_bits(unsigned int source) { return (source & 0xf) << 3; @@ -317,10 +329,12 @@ static inline uint16_t adc_convert_chan_4020_bits(unsigned int channel) enum adc_queue_load_contents { UNIP_BIT = 0x800, /* unipolar/bipolar bit */ ADC_SE_DIFF_BIT = 0x1000, /* single-ended/ differential bit */ - ADC_COMMON_BIT = 0x2000, /* non-referenced single-ended (common-mode input) */ + /* non-referenced single-ended (common-mode input) */ + ADC_COMMON_BIT = 0x2000, QUEUE_EOSEQ_BIT = 0x4000, /* queue end of sequence */ QUEUE_EOSCAN_BIT = 0x8000, /* queue end of scan */ }; + static inline uint16_t adc_chan_bits(unsigned int channel) { return channel & 0x3f; @@ -367,6 +381,7 @@ enum hw_status_contents { EXT_INTR_PENDING_BIT = 0x100, ADC_STOP_BIT = 0x200, }; + static inline uint16_t pipe_full_bits(uint16_t hw_status_bits) { return (hw_status_bits >> 10) & 0x3; @@ -395,9 +410,12 @@ enum i2c_addresses { }; enum range_cal_i2c_contents { - ADC_SRC_4020_MASK = 0x70, /* bits that set what source the adc converter measures */ - BNC_TRIG_THRESHOLD_0V_BIT = 0x80, /* make bnc trig/ext clock threshold 0V instead of 2.5V */ + /* bits that set what source the adc converter measures */ + ADC_SRC_4020_MASK = 0x70, + /* make bnc trig/ext clock threshold 0V instead of 2.5V */ + BNC_TRIG_THRESHOLD_0V_BIT = 0x80, }; + static inline uint8_t adc_src_4020_bits(unsigned int source) { return (source << 4) & ADC_SRC_4020_MASK; @@ -411,91 +429,85 @@ static inline uint8_t attenuate_bit(unsigned int channel) /* analog input ranges for 64xx boards */ static const struct comedi_lrange ai_ranges_64xx = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; /* analog input ranges for 60xx boards */ static const struct comedi_lrange ai_ranges_60xx = { - 4, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - } + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05) + } }; /* analog input ranges for 6030, etc boards */ static const struct comedi_lrange ai_ranges_6030 = { - 14, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2), - BIP_RANGE(1), - BIP_RANGE(0.5), - BIP_RANGE(0.2), - BIP_RANGE(0.1), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1), - UNI_RANGE(0.5), - UNI_RANGE(0.2), - UNI_RANGE(0.1), - } + 14, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.2), + BIP_RANGE(0.1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } }; /* analog input ranges for 6052, etc boards */ static const struct comedi_lrange ai_ranges_6052 = { - 15, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1), - BIP_RANGE(0.5), - BIP_RANGE(0.25), - BIP_RANGE(0.1), - BIP_RANGE(0.05), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2), - UNI_RANGE(1), - UNI_RANGE(0.5), - UNI_RANGE(0.2), - UNI_RANGE(0.1), - } + 15, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.25), + BIP_RANGE(0.1), + BIP_RANGE(0.05), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } }; /* analog input ranges for 4020 board */ static const struct comedi_lrange ai_ranges_4020 = { - 2, - { - BIP_RANGE(5), - BIP_RANGE(1), - } + 2, { + BIP_RANGE(5), + BIP_RANGE(1) + } }; /* analog output ranges */ static const struct comedi_lrange ao_ranges_64xx = { - 4, - { - BIP_RANGE(5), - BIP_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(10), - } + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } }; static const int ao_range_code_64xx[] = { @@ -505,23 +517,15 @@ static const int ao_range_code_64xx[] = { 0x3, }; -static const struct comedi_lrange ao_ranges_60xx = { - 1, - { - BIP_RANGE(10), - } -}; - static const int ao_range_code_60xx[] = { 0x0, }; static const struct comedi_lrange ao_ranges_6030 = { - 2, - { - BIP_RANGE(10), - UNI_RANGE(10), - } + 2, { + BIP_RANGE(10), + UNI_RANGE(10) + } }; static const int ao_range_code_6030[] = { @@ -530,11 +534,10 @@ static const int ao_range_code_6030[] = { }; static const struct comedi_lrange ao_ranges_4020 = { - 2, - { - BIP_RANGE(5), - BIP_RANGE(10), - } + 2, { + BIP_RANGE(5), + BIP_RANGE(10) + } }; static const int ao_range_code_4020[] = { @@ -555,20 +558,51 @@ struct hw_fifo_info { uint16_t fifo_size_reg_mask; }; +enum pcidas64_boardid { + BOARD_PCIDAS6402_16, + BOARD_PCIDAS6402_12, + BOARD_PCIDAS64_M1_16, + BOARD_PCIDAS64_M2_16, + BOARD_PCIDAS64_M3_16, + BOARD_PCIDAS6013, + BOARD_PCIDAS6014, + BOARD_PCIDAS6023, + BOARD_PCIDAS6025, + BOARD_PCIDAS6030, + BOARD_PCIDAS6031, + BOARD_PCIDAS6032, + BOARD_PCIDAS6033, + BOARD_PCIDAS6034, + BOARD_PCIDAS6035, + BOARD_PCIDAS6036, + BOARD_PCIDAS6040, + BOARD_PCIDAS6052, + BOARD_PCIDAS6070, + BOARD_PCIDAS6071, + BOARD_PCIDAS4020_12, + BOARD_PCIDAS6402_16_JR, + BOARD_PCIDAS64_M1_16_JR, + BOARD_PCIDAS64_M2_16_JR, + BOARD_PCIDAS64_M3_16_JR, + BOARD_PCIDAS64_M1_14, + BOARD_PCIDAS64_M2_14, + BOARD_PCIDAS64_M3_14, +}; + struct pcidas64_board { const char *name; - int device_id; /* pci device id */ int ai_se_chans; /* number of ai inputs in single-ended mode */ int ai_bits; /* analog input resolution */ int ai_speed; /* fastest conversion period in ns */ const struct comedi_lrange *ai_range_table; int ao_nchan; /* number of analog out channels */ int ao_bits; /* analog output resolution */ - int ao_scan_speed; /* analog output speed (for a scan, not conversion) */ + int ao_scan_speed; /* analog output scan speed */ const struct comedi_lrange *ao_range_table; const int *ao_range_code; const struct hw_fifo_info *const ai_fifo; - enum register_layout layout; /* different board families have slightly different registers */ + /* different board families have slightly different registers */ + enum register_layout layout; unsigned has_8255:1; }; @@ -598,7 +632,7 @@ static const struct hw_fifo_info ai_fifo_60xx = { #define MAX_AI_DMA_RING_COUNT (0x80000 / DMA_BUFFER_SIZE) #define MIN_AI_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE) #define AO_DMA_RING_COUNT (0x10000 / DMA_BUFFER_SIZE) -static inline unsigned int ai_dma_ring_count(struct pcidas64_board *board) +static inline unsigned int ai_dma_ring_count(const struct pcidas64_board *board) { if (board->layout == LAYOUT_4020) return MAX_AI_DMA_RING_COUNT; @@ -609,475 +643,422 @@ static inline unsigned int ai_dma_ring_count(struct pcidas64_board *board) static const int bytes_in_sample = 2; static const struct pcidas64_board pcidas64_boards[] = { - { - .name = "pci-das6402/16", - .device_id = 0x1d, - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ao_range_table = &ao_ranges_64xx, - .ao_range_code = ao_range_code_64xx, - .ai_fifo = &ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das6402/12", /* XXX check */ - .device_id = 0x1e, - .ai_se_chans = 64, - .ai_bits = 12, - .ai_speed = 5000, - .ao_nchan = 2, - .ao_bits = 12, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ao_range_table = &ao_ranges_64xx, - .ao_range_code = ao_range_code_64xx, - .ai_fifo = &ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m1/16", - .device_id = 0x35, - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 1000, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ao_range_table = &ao_ranges_64xx, - .ao_range_code = ao_range_code_64xx, - .ai_fifo = &ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m2/16", - .device_id = 0x36, - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 500, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ao_range_table = &ao_ranges_64xx, - .ao_range_code = ao_range_code_64xx, - .ai_fifo = &ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m3/16", - .device_id = 0x37, - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 333, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ao_range_table = &ao_ranges_64xx, - .ao_range_code = ao_range_code_64xx, - .ai_fifo = &ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das6013", - .device_id = 0x78, - .ai_se_chans = 16, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 0, - .ao_bits = 16, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_60xx, - .ao_range_table = &ao_ranges_60xx, - .ao_range_code = ao_range_code_60xx, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6014", - .device_id = 0x79, - .ai_se_chans = 16, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 100000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_60xx, - .ao_range_table = &ao_ranges_60xx, - .ao_range_code = ao_range_code_60xx, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6023", - .device_id = 0x5d, - .ai_se_chans = 16, - .ai_bits = 12, - .ai_speed = 5000, - .ao_nchan = 0, - .ao_scan_speed = 100000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_60xx, - .ao_range_table = &ao_ranges_60xx, - .ao_range_code = ao_range_code_60xx, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 1, - }, - { - .name = "pci-das6025", - .device_id = 0x5e, - .ai_se_chans = 16, - .ai_bits = 12, - .ai_speed = 5000, - .ao_nchan = 2, - .ao_bits = 12, - .ao_scan_speed = 100000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_60xx, - .ao_range_table = &ao_ranges_60xx, - .ao_range_code = ao_range_code_60xx, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 1, - }, - { - .name = "pci-das6030", - .device_id = 0x5f, - .ai_se_chans = 16, - .ai_bits = 16, - .ai_speed = 10000, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 10000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_6030, - .ao_range_table = &ao_ranges_6030, - .ao_range_code = ao_range_code_6030, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6031", - .device_id = 0x60, - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 10000, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 10000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_6030, - .ao_range_table = &ao_ranges_6030, - .ao_range_code = ao_range_code_6030, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6032", - .device_id = 0x61, - .ai_se_chans = 16, - .ai_bits = 16, - .ai_speed = 10000, - .ao_nchan = 0, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_6030, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6033", - .device_id = 0x62, - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 10000, - .ao_nchan = 0, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_6030, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6034", - .device_id = 0x63, - .ai_se_chans = 16, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 0, - .ao_scan_speed = 0, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_60xx, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6035", - .device_id = 0x64, - .ai_se_chans = 16, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 2, - .ao_bits = 12, - .ao_scan_speed = 100000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_60xx, - .ao_range_table = &ao_ranges_60xx, - .ao_range_code = ao_range_code_60xx, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6036", - .device_id = 0x6f, - .ai_se_chans = 16, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 100000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_60xx, - .ao_range_table = &ao_ranges_60xx, - .ao_range_code = ao_range_code_60xx, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6040", - .device_id = 0x65, - .ai_se_chans = 16, - .ai_bits = 12, - .ai_speed = 2000, - .ao_nchan = 2, - .ao_bits = 12, - .ao_scan_speed = 1000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_6052, - .ao_range_table = &ao_ranges_6030, - .ao_range_code = ao_range_code_6030, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6052", - .device_id = 0x66, - .ai_se_chans = 16, - .ai_bits = 16, - .ai_speed = 3333, - .ao_nchan = 2, - .ao_bits = 16, - .ao_scan_speed = 3333, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_6052, - .ao_range_table = &ao_ranges_6030, - .ao_range_code = ao_range_code_6030, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6070", - .device_id = 0x67, - .ai_se_chans = 16, - .ai_bits = 12, - .ai_speed = 800, - .ao_nchan = 2, - .ao_bits = 12, - .ao_scan_speed = 1000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_6052, - .ao_range_table = &ao_ranges_6030, - .ao_range_code = ao_range_code_6030, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das6071", - .device_id = 0x68, - .ai_se_chans = 64, - .ai_bits = 12, - .ai_speed = 800, - .ao_nchan = 2, - .ao_bits = 12, - .ao_scan_speed = 1000, - .layout = LAYOUT_60XX, - .ai_range_table = &ai_ranges_6052, - .ao_range_table = &ao_ranges_6030, - .ao_range_code = ao_range_code_6030, - .ai_fifo = &ai_fifo_60xx, - .has_8255 = 0, - }, - { - .name = "pci-das4020/12", - .device_id = 0x52, - .ai_se_chans = 4, - .ai_bits = 12, - .ai_speed = 50, - .ao_bits = 12, - .ao_nchan = 2, - .ao_scan_speed = 0, /* no hardware pacing on ao */ - .layout = LAYOUT_4020, - .ai_range_table = &ai_ranges_4020, - .ao_range_table = &ao_ranges_4020, - .ao_range_code = ao_range_code_4020, - .ai_fifo = &ai_fifo_4020, - .has_8255 = 1, - }, + [BOARD_PCIDAS6402_16] = { + .name = "pci-das6402/16", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS6402_12] = { + .name = "pci-das6402/12", /* XXX check */ + .ai_se_chans = 64, + .ai_bits = 12, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M1_16] = { + .name = "pci-das64/m1/16", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 1000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M2_16] = { + .name = "pci-das64/m2/16", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 500, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M3_16] = { + .name = "pci-das64/m3/16", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 333, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ao_range_table = &ao_ranges_64xx, + .ao_range_code = ao_range_code_64xx, + .ai_fifo = &ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS6013] = { + .name = "pci-das6013", + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 0, + .ao_bits = 16, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &range_bipolar10, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6014] = { + .name = "pci-das6014", + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &range_bipolar10, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6023] = { + .name = "pci-das6023", + .ai_se_chans = 16, + .ai_bits = 12, + .ai_speed = 5000, + .ao_nchan = 0, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &range_bipolar10, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS6025] = { + .name = "pci-das6025", + .ai_se_chans = 16, + .ai_bits = 12, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &range_bipolar10, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS6030] = { + .name = "pci-das6030", + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 10000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6030, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6031] = { + .name = "pci-das6031", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 10000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 10000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6030, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6032] = { + .name = "pci-das6032", + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 10000, + .ao_nchan = 0, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6033] = { + .name = "pci-das6033", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 10000, + .ao_nchan = 0, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6034] = { + .name = "pci-das6034", + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 0, + .ao_scan_speed = 0, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6035] = { + .name = "pci-das6035", + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &range_bipolar10, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6036] = { + .name = "pci-das6036", + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 100000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_60xx, + .ao_range_table = &range_bipolar10, + .ao_range_code = ao_range_code_60xx, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6040] = { + .name = "pci-das6040", + .ai_se_chans = 16, + .ai_bits = 12, + .ai_speed = 2000, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 1000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6052, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6052] = { + .name = "pci-das6052", + .ai_se_chans = 16, + .ai_bits = 16, + .ai_speed = 3333, + .ao_nchan = 2, + .ao_bits = 16, + .ao_scan_speed = 3333, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6052, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6070] = { + .name = "pci-das6070", + .ai_se_chans = 16, + .ai_bits = 12, + .ai_speed = 800, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 1000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6052, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS6071] = { + .name = "pci-das6071", + .ai_se_chans = 64, + .ai_bits = 12, + .ai_speed = 800, + .ao_nchan = 2, + .ao_bits = 12, + .ao_scan_speed = 1000, + .layout = LAYOUT_60XX, + .ai_range_table = &ai_ranges_6052, + .ao_range_table = &ao_ranges_6030, + .ao_range_code = ao_range_code_6030, + .ai_fifo = &ai_fifo_60xx, + .has_8255 = 0, + }, + [BOARD_PCIDAS4020_12] = { + .name = "pci-das4020/12", + .ai_se_chans = 4, + .ai_bits = 12, + .ai_speed = 50, + .ao_bits = 12, + .ao_nchan = 2, + .ao_scan_speed = 0, /* no hardware pacing on ao */ + .layout = LAYOUT_4020, + .ai_range_table = &ai_ranges_4020, + .ao_range_table = &ao_ranges_4020, + .ao_range_code = ao_range_code_4020, + .ai_fifo = &ai_fifo_4020, + .has_8255 = 1, + }, #if 0 - { - .name = "pci-das6402/16/jr", - .device_id = 0 /* XXX, */ - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 5000, - .ao_nchan = 0, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ai_fifo = ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m1/16/jr", - .device_id = 0 /* XXX, */ - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 1000, - .ao_nchan = 0, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ai_fifo = ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m2/16/jr", - .device_id = 0 /* XXX, */ - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 500, - .ao_nchan = 0, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ai_fifo = ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m3/16/jr", - .device_id = 0 /* XXX, */ - .ai_se_chans = 64, - .ai_bits = 16, - .ai_speed = 333, - .ao_nchan = 0, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ai_fifo = ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m1/14", - .device_id = 0, /* XXX */ - .ai_se_chans = 64, - .ai_bits = 14, - .ai_speed = 1000, - .ao_nchan = 2, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ai_fifo = ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m2/14", - .device_id = 0, /* XXX */ - .ai_se_chans = 64, - .ai_bits = 14, - .ai_speed = 500, - .ao_nchan = 2, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ai_fifo = ai_fifo_64xx, - .has_8255 = 1, - }, - { - .name = "pci-das64/m3/14", - .device_id = 0, /* XXX */ - .ai_se_chans = 64, - .ai_bits = 14, - .ai_speed = 333, - .ao_nchan = 2, - .ao_scan_speed = 10000, - .layout = LAYOUT_64XX, - .ai_range_table = &ai_ranges_64xx, - .ai_fifo = ai_fifo_64xx, - .has_8255 = 1, - }, + /* + * The device id for these boards is unknown + */ + + [BOARD_PCIDAS6402_16_JR] = { + .name = "pci-das6402/16/jr", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 5000, + .ao_nchan = 0, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M1_16_JR] = { + .name = "pci-das64/m1/16/jr", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 1000, + .ao_nchan = 0, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M2_16_JR] = { + .name = "pci-das64/m2/16/jr", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 500, + .ao_nchan = 0, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M3_16_JR] = { + .name = "pci-das64/m3/16/jr", + .ai_se_chans = 64, + .ai_bits = 16, + .ai_speed = 333, + .ao_nchan = 0, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M1_14] = { + .name = "pci-das64/m1/14", + .ai_se_chans = 64, + .ai_bits = 14, + .ai_speed = 1000, + .ao_nchan = 2, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M2_14] = { + .name = "pci-das64/m2/14", + .ai_se_chans = 64, + .ai_bits = 14, + .ai_speed = 500, + .ao_nchan = 2, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, + }, + [BOARD_PCIDAS64_M3_14] = { + .name = "pci-das64/m3/14", + .ai_se_chans = 64, + .ai_bits = 14, + .ai_speed = 333, + .ao_nchan = 2, + .ao_scan_speed = 10000, + .layout = LAYOUT_64XX, + .ai_range_table = &ai_ranges_64xx, + .ai_fifo = ai_fifo_64xx, + .has_8255 = 1, + }, #endif }; -static DEFINE_PCI_DEVICE_TABLE(pcidas64_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001d) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x001e) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0035) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0036) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0037) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0052) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005d) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005e) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x005f) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0061) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0062) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0063) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0064) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0066) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0067) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0068) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x006f) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0078) }, - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0079) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pcidas64_pci_table); - -static inline struct pcidas64_board *board(const struct comedi_device *dev) -{ - return (struct pcidas64_board *)dev->board_ptr; -} - static inline unsigned short se_diff_bit_6xxx(struct comedi_device *dev, int use_differential) { - if ((board(dev)->layout == LAYOUT_64XX && !use_differential) || - (board(dev)->layout == LAYOUT_60XX && use_differential)) + const struct pcidas64_board *thisboard = comedi_board(dev); + + if ((thisboard->layout == LAYOUT_64XX && !use_differential) || + (thisboard->layout == LAYOUT_60XX && use_differential)) return ADC_SE_DIFF_BIT; else return 0; }; struct ext_clock_info { - unsigned int divisor; /* master clock divisor to use for scans with external master clock */ - unsigned int chanspec; /* chanspec for master clock input when used as scan begin src */ + /* master clock divisor to use for scans with external master clock */ + unsigned int divisor; + /* chanspec for master clock input when used as scan begin src */ + unsigned int chanspec; }; /* this structure is for data unique to this hardware driver. */ struct pcidas64_private { - - struct pci_dev *hw_dev; /* pointer to board's pci_dev struct */ /* base addresses (physical) */ - resource_size_t plx9080_phys_iobase; resource_size_t main_phys_iobase; resource_size_t dio_counter_phys_iobase; /* base addresses (ioremapped) */ @@ -1087,179 +1068,67 @@ struct pcidas64_private { /* local address (used by dma controller) */ uint32_t local0_iobase; uint32_t local1_iobase; - volatile unsigned int ai_count; /* number of analog input samples remaining */ - uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT]; /* dma buffers for analog input */ - dma_addr_t ai_buffer_bus_addr[MAX_AI_DMA_RING_COUNT]; /* physical addresses of ai dma buffers */ - struct plx_dma_desc *ai_dma_desc; /* array of ai dma descriptors read by plx9080, allocated to get proper alignment */ - dma_addr_t ai_dma_desc_bus_addr; /* physical address of ai dma descriptor array */ - volatile unsigned int ai_dma_index; /* index of the ai dma descriptor/buffer that is currently being used */ - uint16_t *ao_buffer[AO_DMA_RING_COUNT]; /* dma buffers for analog output */ - dma_addr_t ao_buffer_bus_addr[AO_DMA_RING_COUNT]; /* physical addresses of ao dma buffers */ + /* number of analog input samples remaining */ + volatile unsigned int ai_count; + /* dma buffers for analog input */ + uint16_t *ai_buffer[MAX_AI_DMA_RING_COUNT]; + /* physical addresses of ai dma buffers */ + dma_addr_t ai_buffer_bus_addr[MAX_AI_DMA_RING_COUNT]; + /* array of ai dma descriptors read by plx9080, + * allocated to get proper alignment */ + struct plx_dma_desc *ai_dma_desc; + /* physical address of ai dma descriptor array */ + dma_addr_t ai_dma_desc_bus_addr; + /* index of the ai dma descriptor/buffer + * that is currently being used */ + volatile unsigned int ai_dma_index; + /* dma buffers for analog output */ + uint16_t *ao_buffer[AO_DMA_RING_COUNT]; + /* physical addresses of ao dma buffers */ + dma_addr_t ao_buffer_bus_addr[AO_DMA_RING_COUNT]; struct plx_dma_desc *ao_dma_desc; dma_addr_t ao_dma_desc_bus_addr; - volatile unsigned int ao_dma_index; /* keeps track of buffer where the next ao sample should go */ - volatile unsigned long ao_count; /* number of analog output samples remaining */ - volatile unsigned int ao_value[2]; /* remember what the analog outputs are set to, to allow readback */ + /* keeps track of buffer where the next ao sample should go */ + volatile unsigned int ao_dma_index; + /* number of analog output samples remaining */ + volatile unsigned long ao_count; + /* remember what the analog outputs are set to, to allow readback */ + volatile unsigned int ao_value[2]; unsigned int hw_revision; /* stc chip hardware revision number */ - volatile unsigned int intr_enable_bits; /* last bits sent to INTR_ENABLE_REG register */ - volatile uint16_t adc_control1_bits; /* last bits sent to ADC_CONTROL1_REG register */ - volatile uint16_t fifo_size_bits; /* last bits sent to FIFO_SIZE_REG register */ - volatile uint16_t hw_config_bits; /* last bits sent to HW_CONFIG_REG register */ + /* last bits sent to INTR_ENABLE_REG register */ + volatile unsigned int intr_enable_bits; + /* last bits sent to ADC_CONTROL1_REG register */ + volatile uint16_t adc_control1_bits; + /* last bits sent to FIFO_SIZE_REG register */ + volatile uint16_t fifo_size_bits; + /* last bits sent to HW_CONFIG_REG register */ + volatile uint16_t hw_config_bits; volatile uint16_t dac_control1_bits; - volatile uint32_t plx_control_bits; /* last bits written to plx9080 control register */ - volatile uint32_t plx_intcsr_bits; /* last bits written to plx interrupt control and status register */ - volatile int calibration_source; /* index of calibration source readable through ai ch0 */ - volatile uint8_t i2c_cal_range_bits; /* bits written to i2c calibration/range register */ - volatile unsigned int ext_trig_falling; /* configure digital triggers to trigger on falling edge */ + /* last bits written to plx9080 control register */ + volatile uint32_t plx_control_bits; + /* last bits written to plx interrupt control and status register */ + volatile uint32_t plx_intcsr_bits; + /* index of calibration source readable through ai ch0 */ + volatile int calibration_source; + /* bits written to i2c calibration/range register */ + volatile uint8_t i2c_cal_range_bits; + /* configure digital triggers to trigger on falling edge */ + volatile unsigned int ext_trig_falling; /* states of various devices stored to enable read-back */ unsigned int ad8402_state[2]; unsigned int caldac_state[8]; volatile short ai_cmd_running; unsigned int ai_fifo_segment_length; struct ext_clock_info ext_clock; - short ao_bounce_buffer[DAC_FIFO_SIZE]; + unsigned short ao_bounce_buffer[DAC_FIFO_SIZE]; }; -/* inline function that makes it easier to - * access the private structure. - */ -static inline struct pcidas64_private *priv(struct comedi_device *dev) -{ - return dev->private; -} - -/* - * The comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attach/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int detach(struct comedi_device *dev); -static struct comedi_driver driver_cb_pcidas = { - .driver_name = "cb_pcidas64", - .module = THIS_MODULE, - .attach = attach, - .detach = detach, -}; - -static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ao_readback_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *subdev, unsigned int trig_num); -static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static irqreturn_t handle_interrupt(int irq, void *d); -static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static int dio_callback(int dir, int port, int data, unsigned long arg); -static int dio_callback_4020(int dir, int port, int data, unsigned long arg); -static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dio_60xx_config_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int calib_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int calib_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ad8402_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static void ad8402_write(struct comedi_device *dev, unsigned int channel, - unsigned int value); -static int ad8402_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int eeprom_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd); -static unsigned int get_divisor(unsigned int ns, unsigned int flags); -static void i2c_write(struct comedi_device *dev, unsigned int address, - const uint8_t * data, unsigned int length); -static void caldac_write(struct comedi_device *dev, unsigned int channel, - unsigned int value); -static int caldac_8800_write(struct comedi_device *dev, unsigned int address, - uint8_t value); -/* static int dac_1590_write(struct comedi_device *dev, unsigned int dac_a, unsigned int dac_b); */ -static int caldac_i2c_write(struct comedi_device *dev, - unsigned int caldac_channel, unsigned int value); -static void abort_dma(struct comedi_device *dev, unsigned int channel); -static void disable_plx_interrupts(struct comedi_device *dev); -static int set_ai_fifo_size(struct comedi_device *dev, - unsigned int num_samples); -static unsigned int ai_fifo_size(struct comedi_device *dev); -static int set_ai_fifo_segment_length(struct comedi_device *dev, - unsigned int num_entries); -static void disable_ai_pacing(struct comedi_device *dev); -static void disable_ai_interrupts(struct comedi_device *dev); -static void enable_ai_interrupts(struct comedi_device *dev, - const struct comedi_cmd *cmd); -static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags); -static void load_ao_dma(struct comedi_device *dev, - const struct comedi_cmd *cmd); - -static int __devinit driver_cb_pcidas_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_cb_pcidas.driver_name); -} - -static void __devexit driver_cb_pcidas_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_cb_pcidas_pci_driver = { - .id_table = pcidas64_pci_table, - .probe = &driver_cb_pcidas_pci_probe, - .remove = __devexit_p(&driver_cb_pcidas_pci_remove) -}; - -static int __init driver_cb_pcidas_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_cb_pcidas); - if (retval < 0) - return retval; - - driver_cb_pcidas_pci_driver.name = (char *)driver_cb_pcidas.driver_name; - return pci_register_driver(&driver_cb_pcidas_pci_driver); -} - -static void __exit driver_cb_pcidas_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcidas_pci_driver); - comedi_driver_unregister(&driver_cb_pcidas); -} - -module_init(driver_cb_pcidas_init_module); -module_exit(driver_cb_pcidas_cleanup_module); - 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 comedi_krange *range = - &board(dev)->ai_range_table->range[range_index]; + &thisboard->ai_range_table->range[range_index]; unsigned int bits = 0; switch (range->max) { @@ -1302,17 +1171,20 @@ 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) { - if (board(dev)->layout == LAYOUT_4020) + const struct pcidas64_board *thisboard = comedi_board(dev); + + if (thisboard->layout == LAYOUT_4020) return (hw_status_bits >> 13) & 0x7; return (hw_status_bits >> 12) & 0xf; } static void set_dac_range_bits(struct comedi_device *dev, - volatile uint16_t * bits, unsigned int channel, + volatile uint16_t *bits, unsigned int channel, unsigned int range) { - unsigned int code = board(dev)->ao_range_code[range]; + const struct pcidas64_board *thisboard = comedi_board(dev); + unsigned int code = thisboard->ao_range_code[range]; if (channel > 1) comedi_error(dev, "bug! bad channel?"); @@ -1328,53 +1200,84 @@ static inline int ao_cmd_is_supported(const struct pcidas64_board *board) return board->ao_nchan && board->layout != LAYOUT_4020; } +static void abort_dma(struct comedi_device *dev, unsigned int channel) +{ + struct pcidas64_private *devpriv = dev->private; + unsigned long flags; + + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); + + plx9080_abort_dma(devpriv->plx9080_iobase, channel); + + spin_unlock_irqrestore(&dev->spinlock, flags); +} + +static void disable_plx_interrupts(struct comedi_device *dev) +{ + struct pcidas64_private *devpriv = dev->private; + + devpriv->plx_intcsr_bits = 0; + writel(devpriv->plx_intcsr_bits, + devpriv->plx9080_iobase + PLX_INTRCS_REG); +} + +static void disable_ai_interrupts(struct comedi_device *dev) +{ + struct pcidas64_private *devpriv = dev->private; + unsigned long flags; + + spin_lock_irqsave(&dev->spinlock, flags); + devpriv->intr_enable_bits &= + ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT & + ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT & + ~EN_ADC_OVERRUN_BIT & ~ADC_INTR_SRC_MASK; + writew(devpriv->intr_enable_bits, + devpriv->main_iobase + INTR_ENABLE_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); +} + +static void enable_ai_interrupts(struct comedi_device *dev, + const struct comedi_cmd *cmd) +{ + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + uint32_t bits; + unsigned long flags; + + 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) { + /* 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; + } + spin_lock_irqsave(&dev->spinlock, flags); + devpriv->intr_enable_bits |= bits; + writew(devpriv->intr_enable_bits, + devpriv->main_iobase + INTR_ENABLE_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); +} + /* initialize plx9080 chip */ static void init_plx9080(struct comedi_device *dev) { + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; uint32_t bits; - void __iomem *plx_iobase = priv(dev)->plx9080_iobase; - - priv(dev)->plx_control_bits = - readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG); - - /* plx9080 dump */ - DEBUG_PRINT(" plx interrupt status 0x%x\n", - readl(plx_iobase + PLX_INTRCS_REG)); - DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG)); - DEBUG_PRINT(" plx control reg 0x%x\n", priv(dev)->plx_control_bits); - DEBUG_PRINT(" plx mode/arbitration reg 0x%x\n", - readl(plx_iobase + PLX_MARB_REG)); - DEBUG_PRINT(" plx region0 reg 0x%x\n", - readl(plx_iobase + PLX_REGION0_REG)); - DEBUG_PRINT(" plx region1 reg 0x%x\n", - readl(plx_iobase + PLX_REGION1_REG)); - - DEBUG_PRINT(" plx revision 0x%x\n", - readl(plx_iobase + PLX_REVISION_REG)); - DEBUG_PRINT(" plx dma channel 0 mode 0x%x\n", - readl(plx_iobase + PLX_DMA0_MODE_REG)); - DEBUG_PRINT(" plx dma channel 1 mode 0x%x\n", - readl(plx_iobase + PLX_DMA1_MODE_REG)); - DEBUG_PRINT(" plx dma channel 0 pci address 0x%x\n", - readl(plx_iobase + PLX_DMA0_PCI_ADDRESS_REG)); - DEBUG_PRINT(" plx dma channel 0 local address 0x%x\n", - readl(plx_iobase + PLX_DMA0_LOCAL_ADDRESS_REG)); - DEBUG_PRINT(" plx dma channel 0 transfer size 0x%x\n", - readl(plx_iobase + PLX_DMA0_TRANSFER_SIZE_REG)); - DEBUG_PRINT(" plx dma channel 0 descriptor 0x%x\n", - readl(plx_iobase + PLX_DMA0_DESCRIPTOR_REG)); - DEBUG_PRINT(" plx dma channel 0 command status 0x%x\n", - readb(plx_iobase + PLX_DMA0_CS_REG)); - DEBUG_PRINT(" plx dma channel 0 threshold 0x%x\n", - readl(plx_iobase + PLX_DMA0_THRESHOLD_REG)); - DEBUG_PRINT(" plx bigend 0x%x\n", readl(plx_iobase + PLX_BIGEND_REG)); + void __iomem *plx_iobase = devpriv->plx9080_iobase; + + devpriv->plx_control_bits = + readl(devpriv->plx9080_iobase + PLX_CONTROL_REG); #ifdef __BIG_ENDIAN bits = BIGEND_DMA0 | BIGEND_DMA1; #else bits = 0; #endif - writel(bits, priv(dev)->plx9080_iobase + PLX_BIGEND_REG); + writel(bits, devpriv->plx9080_iobase + PLX_BIGEND_REG); disable_plx_interrupts(dev); @@ -1389,9 +1292,11 @@ static void init_plx9080(struct comedi_device *dev) bits |= PLX_EN_BTERM_BIT; /* enable dma chaining */ bits |= PLX_EN_CHAIN_BIT; - /* enable interrupt on dma done (probably don't need this, since chain never finishes) */ + /* enable interrupt on dma done + * (probably don't need this, since chain never finishes) */ bits |= PLX_EN_DMA_DONE_INTR_BIT; - /* don't increment local address during transfers (we are transferring from a fixed fifo register) */ + /* don't increment local address during transfers + * (we are transferring from a fixed fifo register) */ bits |= PLX_LOCAL_ADDR_CONST_BIT; /* route dma interrupt to pci bus */ bits |= PLX_DMA_INTR_PCI_BIT; @@ -1400,321 +1305,225 @@ static void init_plx9080(struct comedi_device *dev) /* enable local burst mode */ bits |= PLX_DMA_LOCAL_BURST_EN_BIT; /* 4020 uses 32 bit dma */ - if (board(dev)->layout == LAYOUT_4020) { + if (thisboard->layout == LAYOUT_4020) bits |= PLX_LOCAL_BUS_32_WIDE_BITS; - } else { /* localspace0 bus is 16 bits wide */ + else /* localspace0 bus is 16 bits wide */ bits |= PLX_LOCAL_BUS_16_WIDE_BITS; - } writel(bits, plx_iobase + PLX_DMA1_MODE_REG); - if (ao_cmd_is_supported(board(dev))) + if (ao_cmd_is_supported(thisboard)) writel(bits, plx_iobase + PLX_DMA0_MODE_REG); /* enable interrupts on plx 9080 */ - priv(dev)->plx_intcsr_bits |= + devpriv->plx_intcsr_bits |= ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | ICS_DMA0_E | ICS_DMA1_E; - writel(priv(dev)->plx_intcsr_bits, - priv(dev)->plx9080_iobase + PLX_INTRCS_REG); + writel(devpriv->plx_intcsr_bits, + devpriv->plx9080_iobase + PLX_INTRCS_REG); } -/* Allocate and initialize the subdevice structures. - */ -static int setup_subdevices(struct comedi_device *dev) +static void disable_ai_pacing(struct comedi_device *dev) { - struct comedi_subdevice *s; - void __iomem *dio_8255_iobase; - int i; + struct pcidas64_private *devpriv = dev->private; + unsigned long flags; - if (alloc_subdevices(dev, 10) < 0) - return -ENOMEM; + disable_ai_interrupts(dev); - s = dev->subdevices + 0; - /* analog input subdevice */ - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DITHER | SDF_CMD_READ; - if (board(dev)->layout == LAYOUT_60XX) - s->subdev_flags |= SDF_COMMON | SDF_DIFF; - else if (board(dev)->layout == LAYOUT_64XX) - s->subdev_flags |= SDF_DIFF; - /* XXX Number of inputs in differential mode is ignored */ - s->n_chan = board(dev)->ai_se_chans; - s->len_chanlist = 0x2000; - s->maxdata = (1 << board(dev)->ai_bits) - 1; - s->range_table = board(dev)->ai_range_table; - s->insn_read = ai_rinsn; - s->insn_config = ai_config_insn; - s->do_cmd = ai_cmd; - s->do_cmdtest = ai_cmdtest; - s->cancel = ai_cancel; - if (board(dev)->layout == LAYOUT_4020) { - uint8_t data; - /* set adc to read from inputs (not internal calibration sources) */ - priv(dev)->i2c_cal_range_bits = adc_src_4020_bits(4); - /* set channels to +-5 volt input ranges */ - for (i = 0; i < s->n_chan; i++) - priv(dev)->i2c_cal_range_bits |= attenuate_bit(i); - data = priv(dev)->i2c_cal_range_bits; - i2c_write(dev, RANGE_CAL_I2C_ADDR, &data, sizeof(data)); - } + spin_lock_irqsave(&dev->spinlock, flags); + devpriv->adc_control1_bits &= ~ADC_SW_GATE_BIT; + writew(devpriv->adc_control1_bits, + devpriv->main_iobase + ADC_CONTROL1_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); - /* analog output subdevice */ - s = dev->subdevices + 1; - if (board(dev)->ao_nchan) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = - SDF_READABLE | SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; - s->n_chan = board(dev)->ao_nchan; - s->maxdata = (1 << board(dev)->ao_bits) - 1; - s->range_table = board(dev)->ao_range_table; - s->insn_read = ao_readback_insn; - s->insn_write = ao_winsn; - if (ao_cmd_is_supported(board(dev))) { - dev->write_subdev = s; - s->do_cmdtest = ao_cmdtest; - s->do_cmd = ao_cmd; - s->len_chanlist = board(dev)->ao_nchan; - s->cancel = ao_cancel; - } - } else { - s->type = COMEDI_SUBD_UNUSED; - } + /* disable pacing, triggering, etc */ + writew(ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT, + devpriv->main_iobase + ADC_CONTROL0_REG); +} - /* digital input */ - s = dev->subdevices + 2; - if (board(dev)->layout == LAYOUT_64XX) { - 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 = di_rbits; - } else - s->type = COMEDI_SUBD_UNUSED; +static int set_ai_fifo_segment_length(struct comedi_device *dev, + unsigned int num_entries) +{ + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + static const int increment_size = 0x100; + const struct hw_fifo_info *const fifo = thisboard->ai_fifo; + unsigned int num_increments; + uint16_t bits; - /* digital output */ - if (board(dev)->layout == LAYOUT_64XX) { - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = do_wbits; - } else - s->type = COMEDI_SUBD_UNUSED; + if (num_entries < increment_size) + num_entries = increment_size; + if (num_entries > fifo->max_segment_length) + num_entries = fifo->max_segment_length; - /* 8255 */ - s = dev->subdevices + 4; - if (board(dev)->has_8255) { - if (board(dev)->layout == LAYOUT_4020) { - dio_8255_iobase = - priv(dev)->main_iobase + I8255_4020_REG; - subdev_8255_init(dev, s, dio_callback_4020, - (unsigned long)dio_8255_iobase); - } else { - dio_8255_iobase = - priv(dev)->dio_counter_iobase + DIO_8255_OFFSET; - subdev_8255_init(dev, s, dio_callback, - (unsigned long)dio_8255_iobase); - } - } else - s->type = COMEDI_SUBD_UNUSED; + /* 1 == 256 entries, 2 == 512 entries, etc */ + num_increments = (num_entries + increment_size / 2) / increment_size; - /* 8 channel dio for 60xx */ - s = dev->subdevices + 5; - if (board(dev)->layout == LAYOUT_60XX) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = dio_60xx_config_insn; - s->insn_bits = dio_60xx_wbits; - } else - s->type = COMEDI_SUBD_UNUSED; + bits = (~(num_increments - 1)) & fifo->fifo_size_reg_mask; + devpriv->fifo_size_bits &= ~fifo->fifo_size_reg_mask; + devpriv->fifo_size_bits |= bits; + writew(devpriv->fifo_size_bits, + devpriv->main_iobase + FIFO_SIZE_REG); - /* caldac */ - s = dev->subdevices + 6; - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = 8; - if (board(dev)->layout == LAYOUT_4020) - s->maxdata = 0xfff; - else - s->maxdata = 0xff; - s->insn_read = calib_read_insn; - s->insn_write = calib_write_insn; - for (i = 0; i < s->n_chan; i++) - caldac_write(dev, i, s->maxdata / 2); + devpriv->ai_fifo_segment_length = num_increments * increment_size; - /* 2 channel ad8402 potentiometer */ - s = dev->subdevices + 7; - if (board(dev)->layout == LAYOUT_64XX) { - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = 2; - s->insn_read = ad8402_read_insn; - s->insn_write = ad8402_write_insn; - s->maxdata = 0xff; - for (i = 0; i < s->n_chan; i++) - ad8402_write(dev, i, s->maxdata / 2); - } else - s->type = COMEDI_SUBD_UNUSED; + return devpriv->ai_fifo_segment_length; +} - /* serial EEPROM, if present */ - s = dev->subdevices + 8; - if (readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG) & CTL_EECHK) { - s->type = COMEDI_SUBD_MEMORY; - s->subdev_flags = SDF_READABLE | SDF_INTERNAL; - s->n_chan = 128; - s->maxdata = 0xffff; - s->insn_read = eeprom_read_insn; - } else - s->type = COMEDI_SUBD_UNUSED; +/* 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); + unsigned int num_fifo_entries; + int retval; + const struct hw_fifo_info *const fifo = thisboard->ai_fifo; - /* user counter subd XXX */ - s = dev->subdevices + 9; - s->type = COMEDI_SUBD_UNUSED; + num_fifo_entries = num_samples / fifo->sample_packing_ratio; - return 0; + retval = set_ai_fifo_segment_length(dev, + num_fifo_entries / + fifo->num_segments); + if (retval < 0) + return retval; + + num_samples = retval * fifo->num_segments * fifo->sample_packing_ratio; + + return num_samples; } -static void disable_plx_interrupts(struct comedi_device *dev) +/* query length of fifo */ +static unsigned int ai_fifo_size(struct comedi_device *dev) { - priv(dev)->plx_intcsr_bits = 0; - writel(priv(dev)->plx_intcsr_bits, - priv(dev)->plx9080_iobase + PLX_INTRCS_REG); + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + + return devpriv->ai_fifo_segment_length * + thisboard->ai_fifo->num_segments * + thisboard->ai_fifo->sample_packing_ratio; } static void init_stc_registers(struct comedi_device *dev) { + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; uint16_t bits; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); - /* bit should be set for 6025, although docs say boards with <= 16 chans should be cleared XXX */ + /* bit should be set for 6025, + * although docs say boards with <= 16 chans should be cleared XXX */ if (1) - priv(dev)->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT; - writew(priv(dev)->adc_control1_bits, - priv(dev)->main_iobase + ADC_CONTROL1_REG); + devpriv->adc_control1_bits |= ADC_QUEUE_CONFIG_BIT; + writew(devpriv->adc_control1_bits, + devpriv->main_iobase + ADC_CONTROL1_REG); /* 6402/16 manual says this register must be initialized to 0xff? */ - writew(0xff, priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); + writew(0xff, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); bits = SLOW_DAC_BIT | DMA_CH_SELECT_BIT; - if (board(dev)->layout == LAYOUT_4020) + if (thisboard->layout == LAYOUT_4020) bits |= INTERNAL_CLOCK_4020_BITS; - priv(dev)->hw_config_bits |= bits; - writew(priv(dev)->hw_config_bits, - priv(dev)->main_iobase + HW_CONFIG_REG); + devpriv->hw_config_bits |= bits; + writew(devpriv->hw_config_bits, + devpriv->main_iobase + HW_CONFIG_REG); - writew(0, priv(dev)->main_iobase + DAQ_SYNC_REG); - writew(0, priv(dev)->main_iobase + CALIBRATION_REG); + writew(0, devpriv->main_iobase + DAQ_SYNC_REG); + writew(0, devpriv->main_iobase + CALIBRATION_REG); spin_unlock_irqrestore(&dev->spinlock, flags); /* set fifos to maximum size */ - priv(dev)->fifo_size_bits |= DAC_FIFO_BITS; + devpriv->fifo_size_bits |= DAC_FIFO_BITS; set_ai_fifo_segment_length(dev, - board(dev)->ai_fifo->max_segment_length); + thisboard->ai_fifo->max_segment_length); - priv(dev)->dac_control1_bits = DAC_OUTPUT_ENABLE_BIT; - priv(dev)->intr_enable_bits = /* EN_DAC_INTR_SRC_BIT | DAC_INTR_QEMPTY_BITS | */ - EN_DAC_DONE_INTR_BIT | EN_DAC_UNDERRUN_BIT; - writew(priv(dev)->intr_enable_bits, - priv(dev)->main_iobase + INTR_ENABLE_REG); + devpriv->dac_control1_bits = DAC_OUTPUT_ENABLE_BIT; + devpriv->intr_enable_bits = + /* EN_DAC_INTR_SRC_BIT | DAC_INTR_QEMPTY_BITS | */ + EN_DAC_DONE_INTR_BIT | EN_DAC_UNDERRUN_BIT; + writew(devpriv->intr_enable_bits, + devpriv->main_iobase + INTR_ENABLE_REG); disable_ai_pacing(dev); }; static int alloc_and_init_dma_members(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; int i; - /* alocate pci dma buffers */ - for (i = 0; i < ai_dma_ring_count(board(dev)); i++) { - priv(dev)->ai_buffer[i] = - pci_alloc_consistent(priv(dev)->hw_dev, DMA_BUFFER_SIZE, - &priv(dev)->ai_buffer_bus_addr[i]); - if (priv(dev)->ai_buffer[i] == NULL) + /* allocate pci dma buffers */ + for (i = 0; i < ai_dma_ring_count(thisboard); i++) { + devpriv->ai_buffer[i] = + pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE, + &devpriv->ai_buffer_bus_addr[i]); + if (devpriv->ai_buffer[i] == NULL) return -ENOMEM; } for (i = 0; i < AO_DMA_RING_COUNT; i++) { - if (ao_cmd_is_supported(board(dev))) { - priv(dev)->ao_buffer[i] = - pci_alloc_consistent(priv(dev)->hw_dev, - DMA_BUFFER_SIZE, - &priv(dev)-> - ao_buffer_bus_addr[i]); - if (priv(dev)->ao_buffer[i] == NULL) + if (ao_cmd_is_supported(thisboard)) { + devpriv->ao_buffer[i] = + pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE, + &devpriv-> + ao_buffer_bus_addr[i]); + if (devpriv->ao_buffer[i] == NULL) return -ENOMEM; } } /* allocate dma descriptors */ - priv(dev)->ai_dma_desc = - pci_alloc_consistent(priv(dev)->hw_dev, - sizeof(struct plx_dma_desc) * - ai_dma_ring_count(board(dev)), - &priv(dev)->ai_dma_desc_bus_addr); - if (priv(dev)->ai_dma_desc == NULL) + devpriv->ai_dma_desc = + pci_alloc_consistent(pcidev, sizeof(struct plx_dma_desc) * + ai_dma_ring_count(thisboard), + &devpriv->ai_dma_desc_bus_addr); + if (devpriv->ai_dma_desc == NULL) return -ENOMEM; - DEBUG_PRINT("ai dma descriptors start at bus addr 0x%x\n", - priv(dev)->ai_dma_desc_bus_addr); - if (ao_cmd_is_supported(board(dev))) { - priv(dev)->ao_dma_desc = - pci_alloc_consistent(priv(dev)->hw_dev, - sizeof(struct plx_dma_desc) * - AO_DMA_RING_COUNT, - &priv(dev)->ao_dma_desc_bus_addr); - if (priv(dev)->ao_dma_desc == NULL) + if (ao_cmd_is_supported(thisboard)) { + devpriv->ao_dma_desc = + pci_alloc_consistent(pcidev, + sizeof(struct plx_dma_desc) * + AO_DMA_RING_COUNT, + &devpriv->ao_dma_desc_bus_addr); + if (devpriv->ao_dma_desc == NULL) return -ENOMEM; - - DEBUG_PRINT("ao dma descriptors start at bus addr 0x%x\n", - priv(dev)->ao_dma_desc_bus_addr); } /* initialize dma descriptors */ - for (i = 0; i < ai_dma_ring_count(board(dev)); i++) { - priv(dev)->ai_dma_desc[i].pci_start_addr = - cpu_to_le32(priv(dev)->ai_buffer_bus_addr[i]); - if (board(dev)->layout == LAYOUT_4020) - priv(dev)->ai_dma_desc[i].local_start_addr = - cpu_to_le32(priv(dev)->local1_iobase + - ADC_FIFO_REG); + for (i = 0; i < ai_dma_ring_count(thisboard); i++) { + devpriv->ai_dma_desc[i].pci_start_addr = + cpu_to_le32(devpriv->ai_buffer_bus_addr[i]); + if (thisboard->layout == LAYOUT_4020) + devpriv->ai_dma_desc[i].local_start_addr = + cpu_to_le32(devpriv->local1_iobase + + ADC_FIFO_REG); else - priv(dev)->ai_dma_desc[i].local_start_addr = - cpu_to_le32(priv(dev)->local0_iobase + - ADC_FIFO_REG); - priv(dev)->ai_dma_desc[i].transfer_size = cpu_to_le32(0); - priv(dev)->ai_dma_desc[i].next = - cpu_to_le32((priv(dev)->ai_dma_desc_bus_addr + ((i + - 1) % - ai_dma_ring_count - (board - (dev))) * - sizeof(priv(dev)->ai_dma_desc[0])) | - PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI); + devpriv->ai_dma_desc[i].local_start_addr = + cpu_to_le32(devpriv->local0_iobase + + ADC_FIFO_REG); + devpriv->ai_dma_desc[i].transfer_size = cpu_to_le32(0); + devpriv->ai_dma_desc[i].next = + cpu_to_le32((devpriv->ai_dma_desc_bus_addr + + ((i + 1) % ai_dma_ring_count(thisboard)) * + sizeof(devpriv->ai_dma_desc[0])) | + PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | + PLX_XFER_LOCAL_TO_PCI); } - if (ao_cmd_is_supported(board(dev))) { + if (ao_cmd_is_supported(thisboard)) { for (i = 0; i < AO_DMA_RING_COUNT; i++) { - priv(dev)->ao_dma_desc[i].pci_start_addr = - cpu_to_le32(priv(dev)->ao_buffer_bus_addr[i]); - priv(dev)->ao_dma_desc[i].local_start_addr = - cpu_to_le32(priv(dev)->local0_iobase + - DAC_FIFO_REG); - priv(dev)->ao_dma_desc[i].transfer_size = - cpu_to_le32(0); - priv(dev)->ao_dma_desc[i].next = - cpu_to_le32((priv(dev)->ao_dma_desc_bus_addr + - ((i + 1) % (AO_DMA_RING_COUNT)) * - sizeof(priv(dev)->ao_dma_desc[0])) | - PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT); + devpriv->ao_dma_desc[i].pci_start_addr = + cpu_to_le32(devpriv->ao_buffer_bus_addr[i]); + devpriv->ao_dma_desc[i].local_start_addr = + cpu_to_le32(devpriv->local0_iobase + + DAC_FIFO_REG); + devpriv->ao_dma_desc[i].transfer_size = cpu_to_le32(0); + devpriv->ao_dma_desc[i].next = + cpu_to_le32((devpriv->ao_dma_desc_bus_addr + + ((i + 1) % (AO_DMA_RING_COUNT)) * + sizeof(devpriv->ao_dma_desc[0])) | + PLX_DESC_IN_PCI_BIT | + PLX_INTR_TERM_COUNT); } } return 0; @@ -1728,233 +1537,164 @@ static inline void warn_external_queue(struct comedi_device *dev) "Use internal AI channel queue (channels must be consecutive and use same range/aref)"); } -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. - */ -static int attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int index; - uint32_t local_range, local_decode; - int retval; - - printk("comedi%d: cb_pcidas64\n", dev->minor); - -/* - * Allocate the private structure area. - */ - if (alloc_private(dev, sizeof(struct pcidas64_private)) < 0) - return -ENOMEM; +/* Their i2c requires a huge delay on setting clock or data high for some reason */ +static const int i2c_high_udelay = 1000; +static const int i2c_low_udelay = 10; -/* - * Probe the device to determine what device in the series it is. - */ +/* set i2c data line high or low */ +static void i2c_set_sda(struct comedi_device *dev, int state) +{ + struct pcidas64_private *devpriv = dev->private; + static const int data_bit = CTL_EE_W; + void __iomem *plx_control_addr = devpriv->plx9080_iobase + + PLX_CONTROL_REG; - for_each_pci_dev(pcidev) { - /* is it not a computer boards card? */ - if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) - continue; - /* loop through cards supported by this driver */ - for (index = 0; index < ARRAY_SIZE(pcidas64_boards); index++) { - if (pcidas64_boards[index].device_id != pcidev->device) - continue; - /* was a particular bus/slot requested? */ - if (it->options[0] || it->options[1]) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - priv(dev)->hw_dev = pcidev; - dev->board_ptr = pcidas64_boards + index; - break; - } - if (dev->board_ptr) - break; - } + if (state) { + /* set data line high */ + devpriv->plx_control_bits &= ~data_bit; + writel(devpriv->plx_control_bits, plx_control_addr); + udelay(i2c_high_udelay); + } else { /* set data line low */ - if (dev->board_ptr == NULL) { - printk - ("No supported ComputerBoards/MeasurementComputing card found\n"); - return -EIO; + devpriv->plx_control_bits |= data_bit; + writel(devpriv->plx_control_bits, plx_control_addr); + udelay(i2c_low_udelay); } +} - printk("Found %s on bus %i, slot %i\n", board(dev)->name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn)); +/* set i2c clock line high or low */ +static void i2c_set_scl(struct comedi_device *dev, int state) +{ + struct pcidas64_private *devpriv = dev->private; + static const int clock_bit = CTL_USERO; + void __iomem *plx_control_addr = devpriv->plx9080_iobase + + PLX_CONTROL_REG; - if (comedi_pci_enable(pcidev, driver_cb_pcidas.driver_name)) { - printk(KERN_WARNING - " failed to enable PCI device and request regions\n"); - return -EIO; - } - pci_set_master(pcidev); + if (state) { + /* set clock line high */ + devpriv->plx_control_bits &= ~clock_bit; + writel(devpriv->plx_control_bits, plx_control_addr); + udelay(i2c_high_udelay); + } else { /* set clock line low */ - /* Initialize dev->board_name */ - dev->board_name = board(dev)->name; - - priv(dev)->plx9080_phys_iobase = - pci_resource_start(pcidev, PLX9080_BADDRINDEX); - priv(dev)->main_phys_iobase = - pci_resource_start(pcidev, MAIN_BADDRINDEX); - priv(dev)->dio_counter_phys_iobase = - pci_resource_start(pcidev, DIO_COUNTER_BADDRINDEX); - - /* remap, won't work with 2.0 kernels but who cares */ - priv(dev)->plx9080_iobase = ioremap(priv(dev)->plx9080_phys_iobase, - pci_resource_len(pcidev, - PLX9080_BADDRINDEX)); - priv(dev)->main_iobase = - ioremap(priv(dev)->main_phys_iobase, - pci_resource_len(pcidev, MAIN_BADDRINDEX)); - priv(dev)->dio_counter_iobase = - ioremap(priv(dev)->dio_counter_phys_iobase, - pci_resource_len(pcidev, DIO_COUNTER_BADDRINDEX)); - - if (!priv(dev)->plx9080_iobase || !priv(dev)->main_iobase - || !priv(dev)->dio_counter_iobase) { - printk(" failed to remap io memory\n"); - return -ENOMEM; + devpriv->plx_control_bits |= clock_bit; + writel(devpriv->plx_control_bits, plx_control_addr); + udelay(i2c_low_udelay); } +} - DEBUG_PRINT(" plx9080 remapped to 0x%p\n", priv(dev)->plx9080_iobase); - DEBUG_PRINT(" main remapped to 0x%p\n", priv(dev)->main_iobase); - DEBUG_PRINT(" diocounter remapped to 0x%p\n", - priv(dev)->dio_counter_iobase); - - /* figure out what local addresses are */ - local_range = - readl(priv(dev)->plx9080_iobase + PLX_LAS0RNG_REG) & LRNG_MEM_MASK; - local_decode = - readl(priv(dev)->plx9080_iobase + - PLX_LAS0MAP_REG) & local_range & LMAP_MEM_MASK; - priv(dev)->local0_iobase = - ((uint32_t) priv(dev)->main_phys_iobase & ~local_range) | - local_decode; - local_range = - readl(priv(dev)->plx9080_iobase + PLX_LAS1RNG_REG) & LRNG_MEM_MASK; - local_decode = - readl(priv(dev)->plx9080_iobase + - PLX_LAS1MAP_REG) & local_range & LMAP_MEM_MASK; - priv(dev)->local1_iobase = - ((uint32_t) priv(dev)->dio_counter_phys_iobase & ~local_range) | - local_decode; - - DEBUG_PRINT(" local 0 io addr 0x%x\n", priv(dev)->local0_iobase); - DEBUG_PRINT(" local 1 io addr 0x%x\n", priv(dev)->local1_iobase); - - retval = alloc_and_init_dma_members(dev); - if (retval < 0) - return retval; +static void i2c_write_byte(struct comedi_device *dev, uint8_t byte) +{ + uint8_t bit; + unsigned int num_bits = 8; - priv(dev)->hw_revision = - hw_revision(dev, readw(priv(dev)->main_iobase + HW_STATUS_REG)); - printk(" stc hardware revision %i\n", priv(dev)->hw_revision); - init_plx9080(dev); - init_stc_registers(dev); - /* get irq */ - if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, - "cb_pcidas64", dev)) { - printk(" unable to allocate irq %u\n", pcidev->irq); - return -EINVAL; + for (bit = 1 << (num_bits - 1); bit; bit >>= 1) { + i2c_set_scl(dev, 0); + if ((byte & bit)) + i2c_set_sda(dev, 1); + else + i2c_set_sda(dev, 0); + i2c_set_scl(dev, 1); } - dev->irq = pcidev->irq; - printk(" irq %u\n", dev->irq); +} - retval = setup_subdevices(dev); - if (retval < 0) - return retval; +/* we can't really read the lines, so fake it */ +static int i2c_read_ack(struct comedi_device *dev) +{ + i2c_set_scl(dev, 0); + i2c_set_sda(dev, 1); + i2c_set_scl(dev, 1); + + return 0; /* return fake acknowledge bit */ +} +/* send start bit */ +static void i2c_start(struct comedi_device *dev) +{ + i2c_set_scl(dev, 1); + i2c_set_sda(dev, 1); + i2c_set_sda(dev, 0); +} - return 0; +/* send stop bit */ +static void i2c_stop(struct comedi_device *dev) +{ + i2c_set_scl(dev, 0); + i2c_set_sda(dev, 0); + i2c_set_scl(dev, 1); + i2c_set_sda(dev, 1); } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int detach(struct comedi_device *dev) +static void i2c_write(struct comedi_device *dev, unsigned int address, + const uint8_t *data, unsigned int length) { + struct pcidas64_private *devpriv = dev->private; unsigned int i; + uint8_t bitstream; + static const int read_bit = 0x1; - printk("comedi%d: cb_pcidas: remove\n", dev->minor); + /* XXX need mutex to prevent simultaneous attempts to access + * eeprom and i2c bus */ - if (dev->irq) - free_irq(dev->irq, dev); - if (priv(dev)) { - if (priv(dev)->hw_dev) { - if (priv(dev)->plx9080_iobase) { - disable_plx_interrupts(dev); - iounmap(priv(dev)->plx9080_iobase); - } - if (priv(dev)->main_iobase) - iounmap(priv(dev)->main_iobase); - if (priv(dev)->dio_counter_iobase) - iounmap(priv(dev)->dio_counter_iobase); - /* free pci dma buffers */ - for (i = 0; i < ai_dma_ring_count(board(dev)); i++) { - if (priv(dev)->ai_buffer[i]) - pci_free_consistent(priv(dev)->hw_dev, - DMA_BUFFER_SIZE, - priv(dev)-> - ai_buffer[i], - priv - (dev)->ai_buffer_bus_addr - [i]); - } - for (i = 0; i < AO_DMA_RING_COUNT; i++) { - if (priv(dev)->ao_buffer[i]) - pci_free_consistent(priv(dev)->hw_dev, - DMA_BUFFER_SIZE, - priv(dev)-> - ao_buffer[i], - priv - (dev)->ao_buffer_bus_addr - [i]); - } - /* free dma descriptors */ - if (priv(dev)->ai_dma_desc) - pci_free_consistent(priv(dev)->hw_dev, - sizeof(struct plx_dma_desc) - * - ai_dma_ring_count(board - (dev)), - priv(dev)->ai_dma_desc, - priv(dev)-> - ai_dma_desc_bus_addr); - if (priv(dev)->ao_dma_desc) - pci_free_consistent(priv(dev)->hw_dev, - sizeof(struct plx_dma_desc) - * AO_DMA_RING_COUNT, - priv(dev)->ao_dma_desc, - priv(dev)-> - ao_dma_desc_bus_addr); - if (priv(dev)->main_phys_iobase) - comedi_pci_disable(priv(dev)->hw_dev); - - pci_dev_put(priv(dev)->hw_dev); + /* make sure we dont send anything to eeprom */ + devpriv->plx_control_bits &= ~CTL_EE_CS; + + i2c_stop(dev); + i2c_start(dev); + + /* send address and write bit */ + bitstream = (address << 1) & ~read_bit; + i2c_write_byte(dev, bitstream); + + /* get acknowledge */ + if (i2c_read_ack(dev) != 0) { + comedi_error(dev, "i2c write failed: no acknowledge"); + i2c_stop(dev); + return; + } + /* write data bytes */ + for (i = 0; i < length; i++) { + i2c_write_byte(dev, data[i]); + if (i2c_read_ack(dev) != 0) { + comedi_error(dev, "i2c write failed: no acknowledge"); + i2c_stop(dev); + return; } } - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 4); + i2c_stop(dev); +} - return 0; +static int cb_pcidas64_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->main_iobase + HW_STATUS_REG); + if (thisboard->layout == LAYOUT_4020) { + status = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG); + if (status) + return 0; + } else { + if (pipe_full_bits(status)) + return 0; + } + return -EBUSY; } static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - unsigned int bits = 0, n, i; + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + unsigned int bits = 0, n; unsigned int channel, range, aref; unsigned long flags; - static const int timeout = 100; + int ret; - DEBUG_PRINT("chanspec 0x%x\n", insn->chanspec); channel = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); aref = CR_AREF(insn->chanspec); @@ -1965,35 +1705,36 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, spin_lock_irqsave(&dev->spinlock, flags); if (insn->chanspec & CR_ALT_FILTER) - priv(dev)->adc_control1_bits |= ADC_DITHER_BIT; + devpriv->adc_control1_bits |= ADC_DITHER_BIT; else - priv(dev)->adc_control1_bits &= ~ADC_DITHER_BIT; - writew(priv(dev)->adc_control1_bits, - priv(dev)->main_iobase + ADC_CONTROL1_REG); + devpriv->adc_control1_bits &= ~ADC_DITHER_BIT; + writew(devpriv->adc_control1_bits, + devpriv->main_iobase + ADC_CONTROL1_REG); spin_unlock_irqrestore(&dev->spinlock, flags); - if (board(dev)->layout != LAYOUT_4020) { + if (thisboard->layout != LAYOUT_4020) { /* use internal queue */ - priv(dev)->hw_config_bits &= ~EXT_QUEUE_BIT; - writew(priv(dev)->hw_config_bits, - priv(dev)->main_iobase + HW_CONFIG_REG); + devpriv->hw_config_bits &= ~EXT_QUEUE_BIT; + writew(devpriv->hw_config_bits, + devpriv->main_iobase + HW_CONFIG_REG); /* ALT_SOURCE is internal calibration reference */ if (insn->chanspec & CR_ALT_SOURCE) { unsigned int cal_en_bit; - DEBUG_PRINT("reading calibration source\n"); - if (board(dev)->layout == LAYOUT_60XX) + if (thisboard->layout == LAYOUT_60XX) cal_en_bit = CAL_EN_60XX_BIT; else cal_en_bit = CAL_EN_64XX_BIT; - /* select internal reference source to connect to channel 0 */ + /* select internal reference source to connect + * to channel 0 */ writew(cal_en_bit | - adc_src_bits(priv(dev)->calibration_source), - priv(dev)->main_iobase + CALIBRATION_REG); + adc_src_bits(devpriv->calibration_source), + devpriv->main_iobase + CALIBRATION_REG); } else { - /* make sure internal calibration source is turned off */ - writew(0, priv(dev)->main_iobase + CALIBRATION_REG); + /* make sure internal calibration source + * is turned off */ + writew(0, devpriv->main_iobase + CALIBRATION_REG); } /* load internal queue */ bits = 0; @@ -2006,77 +1747,59 @@ static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, bits |= adc_chan_bits(channel); /* set stop channel */ writew(adc_chan_bits(channel), - priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG); + devpriv->main_iobase + ADC_QUEUE_HIGH_REG); /* set start channel, and rest of settings */ - writew(bits, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG); + writew(bits, devpriv->main_iobase + ADC_QUEUE_LOAD_REG); } else { - uint8_t old_cal_range_bits = priv(dev)->i2c_cal_range_bits; + uint8_t old_cal_range_bits = devpriv->i2c_cal_range_bits; - priv(dev)->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK; + devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK; if (insn->chanspec & CR_ALT_SOURCE) { - DEBUG_PRINT("reading calibration source\n"); - priv(dev)->i2c_cal_range_bits |= - adc_src_4020_bits(priv(dev)->calibration_source); + devpriv->i2c_cal_range_bits |= + adc_src_4020_bits(devpriv->calibration_source); } else { /* select BNC inputs */ - priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits(4); + devpriv->i2c_cal_range_bits |= adc_src_4020_bits(4); } /* select range */ if (range == 0) - priv(dev)->i2c_cal_range_bits |= attenuate_bit(channel); + devpriv->i2c_cal_range_bits |= attenuate_bit(channel); else - priv(dev)->i2c_cal_range_bits &= - ~attenuate_bit(channel); - /* update calibration/range i2c register only if necessary, as it is very slow */ - if (old_cal_range_bits != priv(dev)->i2c_cal_range_bits) { - uint8_t i2c_data = priv(dev)->i2c_cal_range_bits; + devpriv->i2c_cal_range_bits &= ~attenuate_bit(channel); + /* update calibration/range i2c register only if necessary, + * as it is very slow */ + if (old_cal_range_bits != devpriv->i2c_cal_range_bits) { + uint8_t i2c_data = devpriv->i2c_cal_range_bits; i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data, sizeof(i2c_data)); } - /* 4020 manual asks that sample interval register to be set before writing to convert register. - * Using somewhat arbitrary setting of 4 master clock ticks = 0.1 usec */ - writew(0, - priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); - writew(2, - priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); + /* 4020 manual asks that sample interval register to be set + * before writing to convert register. + * Using somewhat arbitrary setting of 4 master clock ticks + * = 0.1 usec */ + writew(0, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); + writew(2, devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); } for (n = 0; n < insn->n; n++) { /* clear adc buffer (inside loop for 4020 sake) */ - writew(0, priv(dev)->main_iobase + ADC_BUFFER_CLEAR_REG); + writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG); /* trigger conversion, bits sent only matter for 4020 */ writew(adc_convert_chan_4020_bits(CR_CHAN(insn->chanspec)), - priv(dev)->main_iobase + ADC_CONVERT_REG); + devpriv->main_iobase + ADC_CONVERT_REG); /* wait for data */ - for (i = 0; i < timeout; i++) { - bits = readw(priv(dev)->main_iobase + HW_STATUS_REG); - DEBUG_PRINT(" pipe bits 0x%x\n", pipe_full_bits(bits)); - if (board(dev)->layout == LAYOUT_4020) { - if (readw(priv(dev)->main_iobase + - ADC_WRITE_PNTR_REG)) - break; - } else { - if (pipe_full_bits(bits)) - break; - } - udelay(1); - } - DEBUG_PRINT(" looped %i times waiting for data\n", i); - if (i == timeout) { - comedi_error(dev, " analog input read insn timed out"); - printk(" status 0x%x\n", bits); - return -ETIME; - } - if (board(dev)->layout == LAYOUT_4020) - data[n] = - readl(priv(dev)->dio_counter_iobase + - ADC_FIFO_REG) & 0xffff; + ret = comedi_timeout(dev, s, insn, cb_pcidas64_ai_eoc, 0); + if (ret) + return ret; + + if (thisboard->layout == LAYOUT_4020) + data[n] = readl(devpriv->dio_counter_iobase + + ADC_FIFO_REG) & 0xffff; else - data[n] = - readw(priv(dev)->main_iobase + PIPE1_READ_REG); + data[n] = readw(devpriv->main_iobase + PIPE1_READ_REG); } return n; @@ -2085,36 +1808,39 @@ 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); + struct pcidas64_private *devpriv = dev->private; unsigned int source = data[1]; int num_calibration_sources; - if (board(dev)->layout == LAYOUT_60XX) + if (thisboard->layout == LAYOUT_60XX) num_calibration_sources = 16; else num_calibration_sources = 8; if (source >= num_calibration_sources) { - printk("invalid calibration source: %i\n", source); + dev_dbg(dev->class_dev, "invalid calibration source: %i\n", + source); return -EINVAL; } - DEBUG_PRINT("setting calibration source to %i\n", source); - priv(dev)->calibration_source = source; + devpriv->calibration_source = source; return 2; } static int ai_config_block_size(struct comedi_device *dev, unsigned int *data) { + const struct pcidas64_board *thisboard = comedi_board(dev); int fifo_size; - const struct hw_fifo_info *const fifo = board(dev)->ai_fifo; + const struct hw_fifo_info *const fifo = thisboard->ai_fifo; unsigned int block_size, requested_block_size; int retval; requested_block_size = data[1]; if (requested_block_size) { - fifo_size = - requested_block_size * fifo->num_segments / bytes_in_sample; + fifo_size = requested_block_size * fifo->num_segments / + bytes_in_sample; retval = set_ai_fifo_size(dev, fifo_size); if (retval < 0) @@ -2132,6 +1858,7 @@ static int ai_config_block_size(struct comedi_device *dev, unsigned int *data) static int ai_config_master_clock_4020(struct comedi_device *dev, unsigned int *data) { + struct pcidas64_private *devpriv = dev->private; unsigned int divisor = data[4]; int retval = 0; @@ -2142,8 +1869,8 @@ static int ai_config_master_clock_4020(struct comedi_device *dev, switch (data[1]) { case COMEDI_EV_SCAN_BEGIN: - priv(dev)->ext_clock.divisor = divisor; - priv(dev)->ext_clock.chanspec = data[2]; + devpriv->ext_clock.divisor = divisor; + devpriv->ext_clock.chanspec = data[2]; break; default: return -EINVAL; @@ -2158,8 +1885,9 @@ 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); - switch (board(dev)->layout) { + switch (thisboard->layout) { case LAYOUT_4020: return ai_config_master_clock_4020(dev, data); break; @@ -2193,131 +1921,207 @@ static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, return -EINVAL; } +/* Gets nearest achievable timing given master clock speed, does not + * take into account possible minimum/maximum divisor values. Used + * by other timing checking functions. */ +static unsigned int get_divisor(unsigned int ns, unsigned int flags) +{ + unsigned int divisor; + + switch (flags & TRIG_ROUND_MASK) { + case TRIG_ROUND_UP: + divisor = (ns + TIMER_BASE - 1) / TIMER_BASE; + break; + case TRIG_ROUND_DOWN: + divisor = ns / TIMER_BASE; + break; + case TRIG_ROUND_NEAREST: + default: + divisor = (ns + TIMER_BASE / 2) / TIMER_BASE; + break; + } + return divisor; +} + +/* utility function that rounds desired timing to an achievable time, and + * sets cmd members appropriately. + * adc paces conversions from master clock by dividing by (x + 3) where x is 24 bit number + */ +static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) +{ + const struct pcidas64_board *thisboard = comedi_board(dev); + unsigned int convert_divisor = 0, scan_divisor; + static const int min_convert_divisor = 3; + static const int max_convert_divisor = + max_counter_value + min_convert_divisor; + static const int min_scan_divisor_4020 = 2; + unsigned long long max_scan_divisor, min_scan_divisor; + + if (cmd->convert_src == TRIG_TIMER) { + if (thisboard->layout == LAYOUT_4020) { + cmd->convert_arg = 0; + } else { + convert_divisor = get_divisor(cmd->convert_arg, + cmd->flags); + if (convert_divisor > max_convert_divisor) + convert_divisor = max_convert_divisor; + if (convert_divisor < min_convert_divisor) + convert_divisor = min_convert_divisor; + cmd->convert_arg = convert_divisor * TIMER_BASE; + } + } else if (cmd->convert_src == TRIG_NOW) { + cmd->convert_arg = 0; + } + + if (cmd->scan_begin_src == TRIG_TIMER) { + scan_divisor = get_divisor(cmd->scan_begin_arg, cmd->flags); + if (cmd->convert_src == TRIG_TIMER) { + /* XXX check for integer overflows */ + min_scan_divisor = convert_divisor * cmd->chanlist_len; + max_scan_divisor = + (convert_divisor * cmd->chanlist_len - 1) + + max_counter_value; + } else { + min_scan_divisor = min_scan_divisor_4020; + max_scan_divisor = max_counter_value + min_scan_divisor; + } + if (scan_divisor > max_scan_divisor) + scan_divisor = max_scan_divisor; + if (scan_divisor < min_scan_divisor) + scan_divisor = min_scan_divisor; + cmd->scan_begin_arg = scan_divisor * TIMER_BASE; + } + + return; +} + +static int cb_pcidas64_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + const struct pcidas64_board *board = comedi_board(dev); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (aref != aref0) { + dev_dbg(dev->class_dev, + "all elements in chanlist must use the same analog reference\n"); + return -EINVAL; + } + } + + if (board->layout == LAYOUT_4020) { + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "chanlist must use consecutive channels\n"); + return -EINVAL; + } + } + if (cmd->chanlist_len == 3) { + dev_dbg(dev->class_dev, + "chanlist cannot be 3 channels long, use 1, 2, or 4 channels\n"); + return -EINVAL; + } + } + + return 0; +} + static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct pcidas64_board *thisboard = comedi_board(dev); int err = 0; - int tmp; unsigned int tmp_arg, tmp_arg2; - int i; - int aref; unsigned int triggers; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); - tmp = cmd->scan_begin_src; triggers = TRIG_TIMER; - if (board(dev)->layout == LAYOUT_4020) + if (thisboard->layout == LAYOUT_4020) triggers |= TRIG_OTHER; else triggers |= TRIG_FOLLOW; - cmd->scan_begin_src &= triggers; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, triggers); - tmp = cmd->convert_src; triggers = TRIG_TIMER; - if (board(dev)->layout == LAYOUT_4020) + if (thisboard->layout == LAYOUT_4020) triggers |= TRIG_NOW; else triggers |= TRIG_EXT; - cmd->convert_src &= triggers; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, triggers); + 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); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ - - /* uniqueness check */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_OTHER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err++; + /* 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 */ - /* compatibility check */ if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err++; + err |= -EINVAL; if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + switch (cmd->start_src) { + case TRIG_NOW: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* + * start_arg is the CR_CHAN | CR_INVERT of the + * external trigger. + */ + break; + } if (cmd->convert_src == TRIG_TIMER) { - if (board(dev)->layout == LAYOUT_4020) { - if (cmd->convert_arg) { - cmd->convert_arg = 0; - err++; - } + if (thisboard->layout == LAYOUT_4020) { + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); } else { - if (cmd->convert_arg < board(dev)->ai_speed) { - cmd->convert_arg = board(dev)->ai_speed; - err++; - } - if (cmd->scan_begin_src == TRIG_TIMER) { - /* if scans are timed faster than conversion rate allows */ - if (cmd->convert_arg * cmd->chanlist_len > - cmd->scan_begin_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * - cmd->chanlist_len; - err++; - } - } + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + thisboard->ai_speed); + /* if scans are timed faster than conversion rate allows */ + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min( + &cmd->scan_begin_arg, + cmd->convert_arg * + cmd->chanlist_len); } } - if (!cmd->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); switch (cmd->stop_src) { case TRIG_EXT: break; case TRIG_COUNT: - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); break; case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); break; default: break; @@ -2341,36 +2145,9 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - /* make sure user is doesn't change analog reference mid chanlist */ - if (cmd->chanlist) { - aref = CR_AREF(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (aref != CR_AREF(cmd->chanlist[i])) { - comedi_error(dev, - "all elements in chanlist must use the same analog reference"); - err++; - break; - } - } - /* check 4020 chanlist */ - if (board(dev)->layout == LAYOUT_4020) { - unsigned int first_channel = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - first_channel + i) { - comedi_error(dev, - "chanlist must use consecutive channels"); - err++; - break; - } - } - if (cmd->chanlist_len == 3) { - comedi_error(dev, - "chanlist cannot be 3 channels long, use 1, 2, or 4 channels"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas64_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -2392,89 +2169,37 @@ static int use_hw_sample_counter(struct comedi_cmd *cmd) static void setup_sample_counters(struct comedi_device *dev, struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; + if (cmd->stop_src == TRIG_COUNT) { /* set software count */ - priv(dev)->ai_count = cmd->stop_arg * cmd->chanlist_len; + devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len; } /* load hardware conversion counter */ if (use_hw_sample_counter(cmd)) { writew(cmd->stop_arg & 0xffff, - priv(dev)->main_iobase + ADC_COUNT_LOWER_REG); + devpriv->main_iobase + ADC_COUNT_LOWER_REG); writew((cmd->stop_arg >> 16) & 0xff, - priv(dev)->main_iobase + ADC_COUNT_UPPER_REG); + devpriv->main_iobase + ADC_COUNT_UPPER_REG); } else { - writew(1, priv(dev)->main_iobase + ADC_COUNT_LOWER_REG); + writew(1, devpriv->main_iobase + ADC_COUNT_LOWER_REG); } } static inline unsigned int dma_transfer_size(struct comedi_device *dev) { + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; unsigned int num_samples; - num_samples = - priv(dev)->ai_fifo_segment_length * - board(dev)->ai_fifo->sample_packing_ratio; + num_samples = devpriv->ai_fifo_segment_length * + thisboard->ai_fifo->sample_packing_ratio; if (num_samples > DMA_BUFFER_SIZE / sizeof(uint16_t)) num_samples = DMA_BUFFER_SIZE / sizeof(uint16_t); return num_samples; } -static void disable_ai_pacing(struct comedi_device *dev) -{ - unsigned long flags; - - disable_ai_interrupts(dev); - - spin_lock_irqsave(&dev->spinlock, flags); - priv(dev)->adc_control1_bits &= ~ADC_SW_GATE_BIT; - writew(priv(dev)->adc_control1_bits, - priv(dev)->main_iobase + ADC_CONTROL1_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* disable pacing, triggering, etc */ - writew(ADC_DMA_DISABLE_BIT | ADC_SOFT_GATE_BITS | ADC_GATE_LEVEL_BIT, - priv(dev)->main_iobase + ADC_CONTROL0_REG); -} - -static void disable_ai_interrupts(struct comedi_device *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->spinlock, flags); - priv(dev)->intr_enable_bits &= - ~EN_ADC_INTR_SRC_BIT & ~EN_ADC_DONE_INTR_BIT & - ~EN_ADC_ACTIVE_INTR_BIT & ~EN_ADC_STOP_INTR_BIT & - ~EN_ADC_OVERRUN_BIT & ~ADC_INTR_SRC_MASK; - writew(priv(dev)->intr_enable_bits, - priv(dev)->main_iobase + INTR_ENABLE_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - DEBUG_PRINT("intr enable bits 0x%x\n", priv(dev)->intr_enable_bits); -} - -static void enable_ai_interrupts(struct comedi_device *dev, - const struct comedi_cmd *cmd) -{ - uint32_t bits; - unsigned long flags; - - 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) { - /* 4020 doesn't support pio transfers except for fifo dregs */ - if (board(dev)->layout != LAYOUT_4020) - bits |= ADC_INTR_EOSCAN_BITS | EN_ADC_INTR_SRC_BIT; - } - spin_lock_irqsave(&dev->spinlock, flags); - priv(dev)->intr_enable_bits |= bits; - writew(priv(dev)->intr_enable_bits, - priv(dev)->main_iobase + INTR_ENABLE_REG); - DEBUG_PRINT("intr enable bits 0x%x\n", priv(dev)->intr_enable_bits); - spin_unlock_irqrestore(&dev->spinlock, flags); -} - static uint32_t ai_convert_counter_6xxx(const struct comedi_device *dev, const struct comedi_cmd *cmd) { @@ -2486,12 +2211,13 @@ static uint32_t ai_scan_counter_6xxx(struct comedi_device *dev, struct comedi_cmd *cmd) { uint32_t count; + /* figure out how long we need to delay at end of scan */ switch (cmd->scan_begin_src) { case TRIG_TIMER: count = (cmd->scan_begin_arg - - (cmd->convert_arg * (cmd->chanlist_len - 1))) - / TIMER_BASE; + (cmd->convert_arg * (cmd->chanlist_len - 1))) / + TIMER_BASE; break; case TRIG_FOLLOW: count = cmd->convert_arg / TIMER_BASE; @@ -2506,6 +2232,7 @@ static uint32_t ai_scan_counter_6xxx(struct comedi_device *dev, static uint32_t ai_convert_counter_4020(struct comedi_device *dev, struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; unsigned int divisor; switch (cmd->scan_begin_src) { @@ -2513,7 +2240,7 @@ static uint32_t ai_convert_counter_4020(struct comedi_device *dev, divisor = cmd->scan_begin_arg / TIMER_BASE; break; case TRIG_OTHER: - divisor = priv(dev)->ext_clock.divisor; + divisor = devpriv->ext_clock.divisor; break; default: /* should never happen */ comedi_error(dev, "bug! failed to set ai pacing!"); @@ -2528,26 +2255,30 @@ static uint32_t ai_convert_counter_4020(struct comedi_device *dev, static void select_master_clock_4020(struct comedi_device *dev, const struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; + /* select internal/external master clock */ - priv(dev)->hw_config_bits &= ~MASTER_CLOCK_4020_MASK; + devpriv->hw_config_bits &= ~MASTER_CLOCK_4020_MASK; if (cmd->scan_begin_src == TRIG_OTHER) { - int chanspec = priv(dev)->ext_clock.chanspec; + int chanspec = devpriv->ext_clock.chanspec; if (CR_CHAN(chanspec)) - priv(dev)->hw_config_bits |= BNC_CLOCK_4020_BITS; + devpriv->hw_config_bits |= BNC_CLOCK_4020_BITS; else - priv(dev)->hw_config_bits |= EXT_CLOCK_4020_BITS; + devpriv->hw_config_bits |= EXT_CLOCK_4020_BITS; } else { - priv(dev)->hw_config_bits |= INTERNAL_CLOCK_4020_BITS; + devpriv->hw_config_bits |= INTERNAL_CLOCK_4020_BITS; } - writew(priv(dev)->hw_config_bits, - priv(dev)->main_iobase + HW_CONFIG_REG); + writew(devpriv->hw_config_bits, + devpriv->main_iobase + HW_CONFIG_REG); } static void select_master_clock(struct comedi_device *dev, const struct comedi_cmd *cmd) { - switch (board(dev)->layout) { + const struct pcidas64_board *thisboard = comedi_board(dev); + + switch (thisboard->layout) { case LAYOUT_4020: select_master_clock_4020(dev, cmd); break; @@ -2559,6 +2290,7 @@ static void select_master_clock(struct comedi_device *dev, static inline void dma_start_sync(struct comedi_device *dev, unsigned int channel) { + struct pcidas64_private *devpriv = dev->private; unsigned long flags; /* spinlock for plx dma control/status reg */ @@ -2566,23 +2298,25 @@ static inline void dma_start_sync(struct comedi_device *dev, if (channel) writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, - priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); + devpriv->plx9080_iobase + PLX_DMA1_CS_REG); else writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, - priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); + devpriv->plx9080_iobase + PLX_DMA0_CS_REG); spin_unlock_irqrestore(&dev->spinlock, flags); } static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd) { + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; uint32_t convert_counter = 0, scan_counter = 0; check_adc_timing(dev, cmd); select_master_clock(dev, cmd); - if (board(dev)->layout == LAYOUT_4020) { + if (thisboard->layout == LAYOUT_4020) { convert_counter = ai_convert_counter_4020(dev, cmd); } else { convert_counter = ai_convert_counter_6xxx(dev, cmd); @@ -2591,23 +2325,22 @@ static void set_ai_pacing(struct comedi_device *dev, struct comedi_cmd *cmd) /* load lower 16 bits of convert interval */ writew(convert_counter & 0xffff, - priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); - DEBUG_PRINT("convert counter 0x%x\n", convert_counter); + devpriv->main_iobase + ADC_SAMPLE_INTERVAL_LOWER_REG); /* load upper 8 bits of convert interval */ writew((convert_counter >> 16) & 0xff, - priv(dev)->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); + devpriv->main_iobase + ADC_SAMPLE_INTERVAL_UPPER_REG); /* load lower 16 bits of scan delay */ writew(scan_counter & 0xffff, - priv(dev)->main_iobase + ADC_DELAY_INTERVAL_LOWER_REG); + devpriv->main_iobase + ADC_DELAY_INTERVAL_LOWER_REG); /* load upper 8 bits of scan delay */ writew((scan_counter >> 16) & 0xff, - priv(dev)->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG); - DEBUG_PRINT("scan counter 0x%x\n", scan_counter); + devpriv->main_iobase + ADC_DELAY_INTERVAL_UPPER_REG); } static int use_internal_queue_6xxx(const struct comedi_cmd *cmd) { int i; + for (i = 0; i + 1 < cmd->chanlist_len; i++) { if (CR_CHAN(cmd->chanlist[i + 1]) != CR_CHAN(cmd->chanlist[i]) + 1) @@ -2624,14 +2357,16 @@ 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); + struct pcidas64_private *devpriv = dev->private; unsigned short bits; int i; - if (board(dev)->layout != LAYOUT_4020) { + if (thisboard->layout != LAYOUT_4020) { if (use_internal_queue_6xxx(cmd)) { - priv(dev)->hw_config_bits &= ~EXT_QUEUE_BIT; - writew(priv(dev)->hw_config_bits, - priv(dev)->main_iobase + HW_CONFIG_REG); + devpriv->hw_config_bits &= ~EXT_QUEUE_BIT; + writew(devpriv->hw_config_bits, + devpriv->main_iobase + HW_CONFIG_REG); bits = 0; /* set channel */ bits |= adc_chan_bits(CR_CHAN(cmd->chanlist[0])); @@ -2647,30 +2382,30 @@ static int setup_channel_queue(struct comedi_device *dev, /* set stop channel */ writew(adc_chan_bits (CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])), - priv(dev)->main_iobase + ADC_QUEUE_HIGH_REG); + devpriv->main_iobase + ADC_QUEUE_HIGH_REG); /* set start channel, and rest of settings */ writew(bits, - priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG); + devpriv->main_iobase + ADC_QUEUE_LOAD_REG); } else { /* use external queue */ if (dev->write_subdev && dev->write_subdev->busy) { warn_external_queue(dev); return -EBUSY; } - priv(dev)->hw_config_bits |= EXT_QUEUE_BIT; - writew(priv(dev)->hw_config_bits, - priv(dev)->main_iobase + HW_CONFIG_REG); + devpriv->hw_config_bits |= EXT_QUEUE_BIT; + writew(devpriv->hw_config_bits, + devpriv->main_iobase + HW_CONFIG_REG); /* clear DAC buffer to prevent weird interactions */ writew(0, - priv(dev)->main_iobase + DAC_BUFFER_CLEAR_REG); + devpriv->main_iobase + DAC_BUFFER_CLEAR_REG); /* clear queue pointer */ - writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG); + writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); /* load external queue */ for (i = 0; i < cmd->chanlist_len; i++) { bits = 0; /* set channel */ - bits |= - adc_chan_bits(CR_CHAN(cmd->chanlist[i])); + bits |= adc_chan_bits(CR_CHAN(cmd-> + chanlist[i])); /* set gain */ bits |= ai_range_bits_6xxx(dev, CR_RANGE(cmd-> @@ -2686,42 +2421,39 @@ static int setup_channel_queue(struct comedi_device *dev, /* mark end of queue */ if (i == cmd->chanlist_len - 1) bits |= QUEUE_EOSCAN_BIT | - QUEUE_EOSEQ_BIT; + QUEUE_EOSEQ_BIT; writew(bits, - priv(dev)->main_iobase + + devpriv->main_iobase + ADC_QUEUE_FIFO_REG); - DEBUG_PRINT - ("wrote 0x%x to external channel queue\n", - bits); } /* doing a queue clear is not specified in board docs, * but required for reliable operation */ - writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG); + writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); /* prime queue holding register */ - writew(0, priv(dev)->main_iobase + ADC_QUEUE_LOAD_REG); + writew(0, devpriv->main_iobase + ADC_QUEUE_LOAD_REG); } } else { - unsigned short old_cal_range_bits = - priv(dev)->i2c_cal_range_bits; + unsigned short old_cal_range_bits = devpriv->i2c_cal_range_bits; - priv(dev)->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK; + devpriv->i2c_cal_range_bits &= ~ADC_SRC_4020_MASK; /* select BNC inputs */ - priv(dev)->i2c_cal_range_bits |= adc_src_4020_bits(4); + devpriv->i2c_cal_range_bits |= adc_src_4020_bits(4); /* select ranges */ for (i = 0; i < cmd->chanlist_len; i++) { unsigned int channel = CR_CHAN(cmd->chanlist[i]); unsigned int range = CR_RANGE(cmd->chanlist[i]); if (range == 0) - priv(dev)->i2c_cal_range_bits |= - attenuate_bit(channel); + devpriv->i2c_cal_range_bits |= + attenuate_bit(channel); else - priv(dev)->i2c_cal_range_bits &= - ~attenuate_bit(channel); + devpriv->i2c_cal_range_bits &= + ~attenuate_bit(channel); } - /* update calibration/range i2c register only if necessary, as it is very slow */ - if (old_cal_range_bits != priv(dev)->i2c_cal_range_bits) { - uint8_t i2c_data = priv(dev)->i2c_cal_range_bits; + /* update calibration/range i2c register only if necessary, + * as it is very slow */ + if (old_cal_range_bits != devpriv->i2c_cal_range_bits) { + uint8_t i2c_data = devpriv->i2c_cal_range_bits; i2c_write(dev, RANGE_CAL_I2C_ADDR, &i2c_data, sizeof(i2c_data)); } @@ -2733,6 +2465,8 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev, unsigned int dma_channel, unsigned int descriptor_bits) { + struct pcidas64_private *devpriv = dev->private; + /* The transfer size, pci address, and local address registers * are supposedly unused during chained dma, * but I have found that left over values from last operation @@ -2740,25 +2474,27 @@ static inline void load_first_dma_descriptor(struct comedi_device *dev, * block. Initializing them to zero seems to fix the problem. */ if (dma_channel) { writel(0, - priv(dev)->plx9080_iobase + PLX_DMA1_TRANSFER_SIZE_REG); - writel(0, priv(dev)->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG); + devpriv->plx9080_iobase + PLX_DMA1_TRANSFER_SIZE_REG); + writel(0, devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG); writel(0, - priv(dev)->plx9080_iobase + PLX_DMA1_LOCAL_ADDRESS_REG); + devpriv->plx9080_iobase + PLX_DMA1_LOCAL_ADDRESS_REG); writel(descriptor_bits, - priv(dev)->plx9080_iobase + PLX_DMA1_DESCRIPTOR_REG); + devpriv->plx9080_iobase + PLX_DMA1_DESCRIPTOR_REG); } else { writel(0, - priv(dev)->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); - writel(0, priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); + devpriv->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); + writel(0, devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); writel(0, - priv(dev)->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); + devpriv->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); writel(descriptor_bits, - priv(dev)->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); + devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); } } static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; uint32_t bits; @@ -2774,7 +2510,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return retval; /* make sure internal calibration source is turned off */ - writew(0, priv(dev)->main_iobase + CALIBRATION_REG); + writew(0, devpriv->main_iobase + CALIBRATION_REG); set_ai_pacing(dev, cmd); @@ -2784,50 +2520,50 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) spin_lock_irqsave(&dev->spinlock, flags); /* set mode, allow conversions through software gate */ - priv(dev)->adc_control1_bits |= ADC_SW_GATE_BIT; - priv(dev)->adc_control1_bits &= ~ADC_DITHER_BIT; - if (board(dev)->layout != LAYOUT_4020) { - priv(dev)->adc_control1_bits &= ~ADC_MODE_MASK; + devpriv->adc_control1_bits |= ADC_SW_GATE_BIT; + devpriv->adc_control1_bits &= ~ADC_DITHER_BIT; + if (thisboard->layout != LAYOUT_4020) { + devpriv->adc_control1_bits &= ~ADC_MODE_MASK; if (cmd->convert_src == TRIG_EXT) - priv(dev)->adc_control1_bits |= adc_mode_bits(13); /* good old mode 13 */ + /* good old mode 13 */ + devpriv->adc_control1_bits |= adc_mode_bits(13); else - priv(dev)->adc_control1_bits |= adc_mode_bits(8); /* mode 8. What else could you need? */ + /* mode 8. What else could you need? */ + devpriv->adc_control1_bits |= adc_mode_bits(8); } else { - priv(dev)->adc_control1_bits &= ~CHANNEL_MODE_4020_MASK; + devpriv->adc_control1_bits &= ~CHANNEL_MODE_4020_MASK; if (cmd->chanlist_len == 4) - priv(dev)->adc_control1_bits |= FOUR_CHANNEL_4020_BITS; + devpriv->adc_control1_bits |= FOUR_CHANNEL_4020_BITS; else if (cmd->chanlist_len == 2) - priv(dev)->adc_control1_bits |= TWO_CHANNEL_4020_BITS; - priv(dev)->adc_control1_bits &= ~ADC_LO_CHANNEL_4020_MASK; - priv(dev)->adc_control1_bits |= - adc_lo_chan_4020_bits(CR_CHAN(cmd->chanlist[0])); - priv(dev)->adc_control1_bits &= ~ADC_HI_CHANNEL_4020_MASK; - priv(dev)->adc_control1_bits |= - adc_hi_chan_4020_bits(CR_CHAN - (cmd-> - chanlist[cmd->chanlist_len - 1])); + devpriv->adc_control1_bits |= TWO_CHANNEL_4020_BITS; + devpriv->adc_control1_bits &= ~ADC_LO_CHANNEL_4020_MASK; + devpriv->adc_control1_bits |= + adc_lo_chan_4020_bits(CR_CHAN(cmd->chanlist[0])); + devpriv->adc_control1_bits &= ~ADC_HI_CHANNEL_4020_MASK; + devpriv->adc_control1_bits |= + adc_hi_chan_4020_bits(CR_CHAN(cmd->chanlist + [cmd->chanlist_len - 1])); } - writew(priv(dev)->adc_control1_bits, - priv(dev)->main_iobase + ADC_CONTROL1_REG); - DEBUG_PRINT("control1 bits 0x%x\n", priv(dev)->adc_control1_bits); + writew(devpriv->adc_control1_bits, + devpriv->main_iobase + ADC_CONTROL1_REG); spin_unlock_irqrestore(&dev->spinlock, flags); /* clear adc buffer */ - writew(0, priv(dev)->main_iobase + ADC_BUFFER_CLEAR_REG); + writew(0, devpriv->main_iobase + ADC_BUFFER_CLEAR_REG); if ((cmd->flags & TRIG_WAKE_EOS) == 0 || - board(dev)->layout == LAYOUT_4020) { - priv(dev)->ai_dma_index = 0; + thisboard->layout == LAYOUT_4020) { + devpriv->ai_dma_index = 0; /* set dma transfer size */ - for (i = 0; i < ai_dma_ring_count(board(dev)); i++) - priv(dev)->ai_dma_desc[i].transfer_size = - cpu_to_le32(dma_transfer_size(dev) * - sizeof(uint16_t)); + for (i = 0; i < ai_dma_ring_count(thisboard); i++) + devpriv->ai_dma_desc[i].transfer_size = + cpu_to_le32(dma_transfer_size(dev) * + sizeof(uint16_t)); /* give location of first dma descriptor */ load_first_dma_descriptor(dev, 1, - priv(dev)->ai_dma_desc_bus_addr | + devpriv->ai_dma_desc_bus_addr | PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI); @@ -2835,14 +2571,14 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) dma_start_sync(dev, 1); } - if (board(dev)->layout == LAYOUT_4020) { + if (thisboard->layout == LAYOUT_4020) { /* set source for external triggers */ bits = 0; if (cmd->start_src == TRIG_EXT && CR_CHAN(cmd->start_arg)) bits |= EXT_START_TRIG_BNC_BIT; if (cmd->stop_src == TRIG_EXT && CR_CHAN(cmd->stop_arg)) bits |= EXT_STOP_TRIG_BNC_BIT; - writew(bits, priv(dev)->main_iobase + DAQ_ATRIG_LOW_4020_REG); + writew(bits, devpriv->main_iobase + DAQ_ATRIG_LOW_4020_REG); } spin_lock_irqsave(&dev->spinlock, flags); @@ -2860,18 +2596,15 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) bits |= ADC_START_TRIG_SOFT_BITS; if (use_hw_sample_counter(cmd)) bits |= ADC_SAMPLE_COUNTER_EN_BIT; - writew(bits, priv(dev)->main_iobase + ADC_CONTROL0_REG); - DEBUG_PRINT("control0 bits 0x%x\n", bits); + writew(bits, devpriv->main_iobase + ADC_CONTROL0_REG); - priv(dev)->ai_cmd_running = 1; + devpriv->ai_cmd_running = 1; spin_unlock_irqrestore(&dev->spinlock, flags); /* start acquisition */ - if (cmd->start_src == TRIG_NOW) { - writew(0, priv(dev)->main_iobase + ADC_START_REG); - DEBUG_PRINT("soft trig\n"); - } + if (cmd->start_src == TRIG_NOW) + writew(0, devpriv->main_iobase + ADC_START_REG); return 0; } @@ -2879,6 +2612,7 @@ static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* read num_samples from 16 bit wide ai fifo */ static void pio_drain_ai_fifo_16(struct comedi_device *dev) { + struct pcidas64_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -2889,63 +2623,60 @@ static void pio_drain_ai_fifo_16(struct comedi_device *dev) do { /* get least significant 15 bits */ - read_index = - readw(priv(dev)->main_iobase + ADC_READ_PNTR_REG) & 0x7fff; - write_index = - readw(priv(dev)->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff; - /* Get most significant bits (grey code). Different boards use different code - * so use a scheme that doesn't depend on encoding. This read must + read_index = readw(devpriv->main_iobase + ADC_READ_PNTR_REG) & + 0x7fff; + write_index = readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) & + 0x7fff; + /* Get most significant bits (grey code). + * Different boards use different code so use a scheme + * that doesn't depend on encoding. This read must * occur after reading least significant 15 bits to avoid race * with fifo switching to next segment. */ - prepost_bits = readw(priv(dev)->main_iobase + PREPOST_REG); + prepost_bits = readw(devpriv->main_iobase + PREPOST_REG); - /* if read and write pointers are not on the same fifo segment, read to the - * end of the read segment */ + /* if read and write pointers are not on the same fifo segment, + * read to the end of the read segment */ read_segment = adc_upper_read_ptr_code(prepost_bits); write_segment = adc_upper_write_ptr_code(prepost_bits); - DEBUG_PRINT(" rd seg %i, wrt seg %i, rd idx %i, wrt idx %i\n", - read_segment, write_segment, read_index, - write_index); - if (read_segment != write_segment) num_samples = - priv(dev)->ai_fifo_segment_length - read_index; + devpriv->ai_fifo_segment_length - read_index; else num_samples = write_index - read_index; if (cmd->stop_src == TRIG_COUNT) { - if (priv(dev)->ai_count == 0) + if (devpriv->ai_count == 0) break; - if (num_samples > priv(dev)->ai_count) - num_samples = priv(dev)->ai_count; + if (num_samples > devpriv->ai_count) + num_samples = devpriv->ai_count; - priv(dev)->ai_count -= num_samples; + devpriv->ai_count -= num_samples; } if (num_samples < 0) { - printk(" cb_pcidas64: bug! num_samples < 0\n"); + dev_err(dev->class_dev, + "cb_pcidas64: bug! num_samples < 0\n"); break; } - DEBUG_PRINT(" read %i samples from fifo\n", num_samples); - for (i = 0; i < num_samples; i++) { cfc_write_to_buffer(s, - readw(priv(dev)->main_iobase + + readw(devpriv->main_iobase + ADC_FIFO_REG)); } } while (read_segment != write_segment); } -/* Read from 32 bit wide ai fifo of 4020 - deal with insane grey coding of pointers. - * The pci-4020 hardware only supports - * dma transfers (it only supports the use of pio for draining the last remaining - * points from the fifo when a data acquisition operation has completed). +/* Read from 32 bit wide ai fifo of 4020 - deal with insane grey coding of + * pointers. The pci-4020 hardware only supports dma transfers (it only + * supports the use of pio for draining the last remaining points from the + * fifo when a data acquisition operation has completed). */ static void pio_drain_ai_fifo_32(struct comedi_device *dev) { + struct pcidas64_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -2953,33 +2684,35 @@ static void pio_drain_ai_fifo_32(struct comedi_device *dev) unsigned int max_transfer = 100000; uint32_t fifo_data; int write_code = - readw(priv(dev)->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff; + readw(devpriv->main_iobase + ADC_WRITE_PNTR_REG) & 0x7fff; int read_code = - readw(priv(dev)->main_iobase + ADC_READ_PNTR_REG) & 0x7fff; + readw(devpriv->main_iobase + ADC_READ_PNTR_REG) & 0x7fff; if (cmd->stop_src == TRIG_COUNT) { - if (max_transfer > priv(dev)->ai_count) - max_transfer = priv(dev)->ai_count; + if (max_transfer > devpriv->ai_count) + max_transfer = devpriv->ai_count; } for (i = 0; read_code != write_code && i < max_transfer;) { - fifo_data = readl(priv(dev)->dio_counter_iobase + ADC_FIFO_REG); + fifo_data = readl(devpriv->dio_counter_iobase + ADC_FIFO_REG); cfc_write_to_buffer(s, fifo_data & 0xffff); i++; if (i < max_transfer) { cfc_write_to_buffer(s, (fifo_data >> 16) & 0xffff); i++; } - read_code = - readw(priv(dev)->main_iobase + ADC_READ_PNTR_REG) & 0x7fff; + read_code = readw(devpriv->main_iobase + ADC_READ_PNTR_REG) & + 0x7fff; } - priv(dev)->ai_count -= i; + devpriv->ai_count -= i; } /* empty fifo */ static void pio_drain_ai_fifo(struct comedi_device *dev) { - if (board(dev)->layout == LAYOUT_4020) + const struct pcidas64_board *thisboard = comedi_board(dev); + + if (thisboard->layout == LAYOUT_4020) pio_drain_ai_fifo_32(dev); else pio_drain_ai_fifo_16(dev); @@ -2987,7 +2720,10 @@ 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); + struct pcidas64_private *devpriv = dev->private; struct comedi_async *async = dev->read_subdev->async; + struct comedi_cmd *cmd = &async->cmd; uint32_t next_transfer_addr; int j; int num_samples = 0; @@ -2995,46 +2731,42 @@ static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) if (channel) pci_addr_reg = - priv(dev)->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG; + devpriv->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG; else pci_addr_reg = - priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; + devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; /* loop until we have read all the full buffers */ for (j = 0, next_transfer_addr = readl(pci_addr_reg); (next_transfer_addr < - priv(dev)->ai_buffer_bus_addr[priv(dev)->ai_dma_index] - || next_transfer_addr >= - priv(dev)->ai_buffer_bus_addr[priv(dev)->ai_dma_index] + - DMA_BUFFER_SIZE) && j < ai_dma_ring_count(board(dev)); j++) { + devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] || + next_transfer_addr >= + devpriv->ai_buffer_bus_addr[devpriv->ai_dma_index] + + DMA_BUFFER_SIZE) && j < ai_dma_ring_count(thisboard); j++) { /* transfer data from dma buffer to comedi buffer */ num_samples = dma_transfer_size(dev); - if (async->cmd.stop_src == TRIG_COUNT) { - if (num_samples > priv(dev)->ai_count) - num_samples = priv(dev)->ai_count; - priv(dev)->ai_count -= num_samples; + if (cmd->stop_src == TRIG_COUNT) { + if (num_samples > devpriv->ai_count) + num_samples = devpriv->ai_count; + devpriv->ai_count -= num_samples; } cfc_write_array_to_buffer(dev->read_subdev, - priv(dev)->ai_buffer[priv(dev)-> - ai_dma_index], + devpriv->ai_buffer[devpriv-> + ai_dma_index], num_samples * sizeof(uint16_t)); - priv(dev)->ai_dma_index = - (priv(dev)->ai_dma_index + - 1) % ai_dma_ring_count(board(dev)); - - DEBUG_PRINT("next buffer addr 0x%lx\n", - (unsigned long)priv(dev)-> - ai_buffer_bus_addr[priv(dev)->ai_dma_index]); - DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr); + devpriv->ai_dma_index = (devpriv->ai_dma_index + 1) % + ai_dma_ring_count(thisboard); } - /* XXX check for dma ring buffer overrun (use end-of-chain bit to mark last - * unused buffer) */ + /* XXX check for dma ring buffer overrun + * (use end-of-chain bit to mark last unused buffer) */ } static void handle_ai_interrupt(struct comedi_device *dev, unsigned short status, unsigned int plx_status) { + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; @@ -3048,37 +2780,30 @@ static void handle_ai_interrupt(struct comedi_device *dev, } /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); + dma1_status = readb(devpriv->plx9080_iobase + PLX_DMA1_CS_REG); if (plx_status & ICS_DMA1_A) { /* dma chan 1 interrupt */ writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); - DEBUG_PRINT("dma1 status 0x%x\n", dma1_status); + devpriv->plx9080_iobase + PLX_DMA1_CS_REG); if (dma1_status & PLX_DMA_EN_BIT) drain_dma_buffers(dev, 1); - - DEBUG_PRINT(" cleared dma ch1 interrupt\n"); } spin_unlock_irqrestore(&dev->spinlock, flags); - if (status & ADC_DONE_BIT) - DEBUG_PRINT("adc done interrupt\n"); - /* drain fifo with pio */ if ((status & ADC_DONE_BIT) || ((cmd->flags & TRIG_WAKE_EOS) && (status & ADC_INTR_PENDING_BIT) && - (board(dev)->layout != LAYOUT_4020))) { - DEBUG_PRINT("pio fifo drain\n"); + (thisboard->layout != LAYOUT_4020))) { spin_lock_irqsave(&dev->spinlock, flags); - if (priv(dev)->ai_cmd_running) { + if (devpriv->ai_cmd_running) { spin_unlock_irqrestore(&dev->spinlock, flags); pio_drain_ai_fifo(dev); } else spin_unlock_irqrestore(&dev->spinlock, flags); } /* if we are have all the data, then quit */ - if ((cmd->stop_src == TRIG_COUNT && (int)priv(dev)->ai_count <= 0) || + if ((cmd->stop_src == TRIG_COUNT && (int)devpriv->ai_count <= 0) || (cmd->stop_src == TRIG_EXT && (status & ADC_STOP_BIT))) { async->events |= COMEDI_CB_EOA; } @@ -3088,29 +2813,31 @@ static void handle_ai_interrupt(struct comedi_device *dev, static inline unsigned int prev_ao_dma_index(struct comedi_device *dev) { + struct pcidas64_private *devpriv = dev->private; unsigned int buffer_index; - if (priv(dev)->ao_dma_index == 0) + if (devpriv->ao_dma_index == 0) buffer_index = AO_DMA_RING_COUNT - 1; else - buffer_index = priv(dev)->ao_dma_index - 1; + buffer_index = devpriv->ao_dma_index - 1; return buffer_index; } static int last_ao_dma_load_completed(struct comedi_device *dev) { + struct pcidas64_private *devpriv = dev->private; unsigned int buffer_index; unsigned int transfer_address; unsigned short dma_status; buffer_index = prev_ao_dma_index(dev); - dma_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); + dma_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG); if ((dma_status & PLX_DMA_DONE_BIT) == 0) return 0; transfer_address = - readl(priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); - if (transfer_address != priv(dev)->ao_buffer_bus_addr[buffer_index]) + readl(devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); + if (transfer_address != devpriv->ao_buffer_bus_addr[buffer_index]) return 0; return 1; @@ -3119,10 +2846,12 @@ static int last_ao_dma_load_completed(struct comedi_device *dev) static int ao_stopped_by_error(struct comedi_device *dev, const struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; + if (cmd->stop_src == TRIG_NONE) return 1; if (cmd->stop_src == TRIG_COUNT) { - if (priv(dev)->ao_count) + if (devpriv->ao_count) return 1; if (last_ao_dma_load_completed(dev) == 0) return 1; @@ -3144,20 +2873,86 @@ static inline int ao_dma_needs_restart(struct comedi_device *dev, static void restart_ao_dma(struct comedi_device *dev) { + struct pcidas64_private *devpriv = dev->private; unsigned int dma_desc_bits; dma_desc_bits = - readl(priv(dev)->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); + readl(devpriv->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); dma_desc_bits &= ~PLX_END_OF_CHAIN_BIT; - DEBUG_PRINT("restarting ao dma, descriptor reg 0x%x\n", dma_desc_bits); load_first_dma_descriptor(dev, 0, dma_desc_bits); dma_start_sync(dev, 0); } +static unsigned int load_ao_dma_buffer(struct comedi_device *dev, + const struct comedi_cmd *cmd) +{ + struct pcidas64_private *devpriv = dev->private; + unsigned int num_bytes, buffer_index, prev_buffer_index; + unsigned int next_bits; + + buffer_index = devpriv->ao_dma_index; + prev_buffer_index = prev_ao_dma_index(dev); + + num_bytes = comedi_buf_read_n_available(dev->write_subdev); + if (num_bytes > DMA_BUFFER_SIZE) + num_bytes = DMA_BUFFER_SIZE; + if (cmd->stop_src == TRIG_COUNT && num_bytes > devpriv->ao_count) + num_bytes = devpriv->ao_count; + num_bytes -= num_bytes % bytes_in_sample; + + if (num_bytes == 0) + return 0; + + num_bytes = cfc_read_array_from_buffer(dev->write_subdev, + devpriv-> + ao_buffer[buffer_index], + num_bytes); + devpriv->ao_dma_desc[buffer_index].transfer_size = + cpu_to_le32(num_bytes); + /* set end of chain bit so we catch underruns */ + next_bits = le32_to_cpu(devpriv->ao_dma_desc[buffer_index].next); + next_bits |= PLX_END_OF_CHAIN_BIT; + devpriv->ao_dma_desc[buffer_index].next = cpu_to_le32(next_bits); + /* clear end of chain bit on previous buffer now that we have set it + * for the last buffer */ + next_bits = le32_to_cpu(devpriv->ao_dma_desc[prev_buffer_index].next); + next_bits &= ~PLX_END_OF_CHAIN_BIT; + devpriv->ao_dma_desc[prev_buffer_index].next = cpu_to_le32(next_bits); + + devpriv->ao_dma_index = (buffer_index + 1) % AO_DMA_RING_COUNT; + devpriv->ao_count -= num_bytes; + + return num_bytes; +} + +static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) +{ + struct pcidas64_private *devpriv = dev->private; + unsigned int num_bytes; + unsigned int next_transfer_addr; + void __iomem *pci_addr_reg = + devpriv->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; + unsigned int buffer_index; + + do { + buffer_index = devpriv->ao_dma_index; + /* don't overwrite data that hasn't been transferred yet */ + next_transfer_addr = readl(pci_addr_reg); + if (next_transfer_addr >= + devpriv->ao_buffer_bus_addr[buffer_index] && + next_transfer_addr < + devpriv->ao_buffer_bus_addr[buffer_index] + + DMA_BUFFER_SIZE) + return; + num_bytes = load_ao_dma_buffer(dev, cmd); + } while (num_bytes >= DMA_BUFFER_SIZE); +} + static void handle_ao_interrupt(struct comedi_device *dev, unsigned short status, unsigned int plx_status) { + struct pcidas64_private *devpriv = dev->private; struct comedi_subdevice *s = dev->write_subdev; struct comedi_async *async; struct comedi_cmd *cmd; @@ -3172,37 +2967,30 @@ static void handle_ao_interrupt(struct comedi_device *dev, /* spin lock makes sure no one else changes plx dma control reg */ spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); + dma0_status = readb(devpriv->plx9080_iobase + PLX_DMA0_CS_REG); if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ - if ((dma0_status & PLX_DMA_EN_BIT) - && !(dma0_status & PLX_DMA_DONE_BIT)) + if ((dma0_status & PLX_DMA_EN_BIT) && + !(dma0_status & PLX_DMA_DONE_BIT)) writeb(PLX_DMA_EN_BIT | PLX_CLEAR_DMA_INTR_BIT, - priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); + devpriv->plx9080_iobase + PLX_DMA0_CS_REG); else writeb(PLX_CLEAR_DMA_INTR_BIT, - priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); + devpriv->plx9080_iobase + PLX_DMA0_CS_REG); spin_unlock_irqrestore(&dev->spinlock, flags); - DEBUG_PRINT("dma0 status 0x%x\n", dma0_status); if (dma0_status & PLX_DMA_EN_BIT) { load_ao_dma(dev, cmd); /* try to recover from dma end-of-chain event */ if (ao_dma_needs_restart(dev, dma0_status)) restart_ao_dma(dev); } - DEBUG_PRINT(" cleared dma ch0 interrupt\n"); - } else + } else { spin_unlock_irqrestore(&dev->spinlock, flags); + } if ((status & DAC_DONE_BIT)) { async->events |= COMEDI_CB_EOA; if (ao_stopped_by_error(dev, cmd)) async->events |= COMEDI_CB_ERROR; - DEBUG_PRINT("plx dma0 desc reg 0x%x\n", - readl(priv(dev)->plx9080_iobase + - PLX_DMA0_DESCRIPTOR_REG)); - DEBUG_PRINT("plx dma0 address reg 0x%x\n", - readl(priv(dev)->plx9080_iobase + - PLX_DMA0_PCI_ADDRESS_REG)); } cfc_handle_events(dev, s); } @@ -3210,97 +2998,80 @@ static void handle_ao_interrupt(struct comedi_device *dev, static irqreturn_t handle_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct pcidas64_private *devpriv = dev->private; unsigned short status; uint32_t plx_status; uint32_t plx_bits; - plx_status = readl(priv(dev)->plx9080_iobase + PLX_INTRCS_REG); - status = readw(priv(dev)->main_iobase + HW_STATUS_REG); - - DEBUG_PRINT("cb_pcidas64: hw status 0x%x ", status); - DEBUG_PRINT("plx status 0x%x\n", plx_status); + plx_status = readl(devpriv->plx9080_iobase + PLX_INTRCS_REG); + status = readw(devpriv->main_iobase + HW_STATUS_REG); /* an interrupt before all the postconfig stuff gets done could * cause a NULL dereference if we continue through the * interrupt handler */ - if (dev->attached == 0) { - DEBUG_PRINT("cb_pcidas64: premature interrupt, ignoring", - status); + if (!dev->attached) return IRQ_HANDLED; - } + handle_ai_interrupt(dev, status, plx_status); handle_ao_interrupt(dev, status, plx_status); /* clear possible plx9080 interrupt sources */ if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ - plx_bits = readl(priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG); - writel(plx_bits, priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG); - DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits); + plx_bits = readl(devpriv->plx9080_iobase + PLX_DBR_OUT_REG); + writel(plx_bits, devpriv->plx9080_iobase + PLX_DBR_OUT_REG); } - DEBUG_PRINT("exiting handler\n"); - return IRQ_HANDLED; } -static void abort_dma(struct comedi_device *dev, unsigned int channel) -{ - unsigned long flags; - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - - plx9080_abort_dma(priv(dev)->plx9080_iobase, channel); - - spin_unlock_irqrestore(&dev->spinlock, flags); -} - static int ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcidas64_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); - if (priv(dev)->ai_cmd_running == 0) { + if (devpriv->ai_cmd_running == 0) { spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } - priv(dev)->ai_cmd_running = 0; + devpriv->ai_cmd_running = 0; spin_unlock_irqrestore(&dev->spinlock, flags); disable_ai_pacing(dev); abort_dma(dev, 1); - DEBUG_PRINT("ai canceled\n"); return 0; } 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); + struct pcidas64_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); int range = CR_RANGE(insn->chanspec); /* do some initializing */ - writew(0, priv(dev)->main_iobase + DAC_CONTROL0_REG); + writew(0, devpriv->main_iobase + DAC_CONTROL0_REG); /* set range */ - set_dac_range_bits(dev, &priv(dev)->dac_control1_bits, chan, range); - writew(priv(dev)->dac_control1_bits, - priv(dev)->main_iobase + DAC_CONTROL1_REG); + set_dac_range_bits(dev, &devpriv->dac_control1_bits, chan, range); + writew(devpriv->dac_control1_bits, + devpriv->main_iobase + DAC_CONTROL1_REG); /* write to channel */ - if (board(dev)->layout == LAYOUT_4020) { + if (thisboard->layout == LAYOUT_4020) { writew(data[0] & 0xff, - priv(dev)->main_iobase + dac_lsb_4020_reg(chan)); + devpriv->main_iobase + dac_lsb_4020_reg(chan)); writew((data[0] >> 8) & 0xf, - priv(dev)->main_iobase + dac_msb_4020_reg(chan)); + devpriv->main_iobase + dac_msb_4020_reg(chan)); } else { - writew(data[0], priv(dev)->main_iobase + dac_convert_reg(chan)); + writew(data[0], devpriv->main_iobase + dac_convert_reg(chan)); } /* remember output value */ - priv(dev)->ao_value[chan] = data[0]; + devpriv->ao_value[chan] = data[0]; return 1; } @@ -3309,7 +3080,9 @@ static int ao_readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - data[0] = priv(dev)->ao_value[CR_CHAN(insn->chanspec)]; + struct pcidas64_private *devpriv = dev->private; + + data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; return 1; } @@ -3317,8 +3090,9 @@ static int ao_readback_insn(struct comedi_device *dev, static void set_dac_control0_reg(struct comedi_device *dev, const struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; unsigned int bits = DAC_ENABLE_BIT | WAVEFORM_GATE_LEVEL_BIT | - WAVEFORM_GATE_ENABLE_BIT | WAVEFORM_GATE_SELECT_BIT; + WAVEFORM_GATE_ENABLE_BIT | WAVEFORM_GATE_SELECT_BIT; if (cmd->start_src == TRIG_EXT) { bits |= WAVEFORM_TRIG_EXT_BITS; @@ -3332,12 +3106,13 @@ static void set_dac_control0_reg(struct comedi_device *dev, if (cmd->scan_begin_arg & CR_INVERT) bits |= DAC_EXT_UPDATE_FALLING_BIT; } - writew(bits, priv(dev)->main_iobase + DAC_CONTROL0_REG); + writew(bits, devpriv->main_iobase + DAC_CONTROL0_REG); } static void set_dac_control1_reg(struct comedi_device *dev, const struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; int i; for (i = 0; i < cmd->chanlist_len; i++) { @@ -3345,17 +3120,18 @@ static void set_dac_control1_reg(struct comedi_device *dev, channel = CR_CHAN(cmd->chanlist[i]); range = CR_RANGE(cmd->chanlist[i]); - set_dac_range_bits(dev, &priv(dev)->dac_control1_bits, channel, + set_dac_range_bits(dev, &devpriv->dac_control1_bits, channel, range); } - priv(dev)->dac_control1_bits |= DAC_SW_GATE_BIT; - writew(priv(dev)->dac_control1_bits, - priv(dev)->main_iobase + DAC_CONTROL1_REG); + devpriv->dac_control1_bits |= DAC_SW_GATE_BIT; + writew(devpriv->dac_control1_bits, + devpriv->main_iobase + DAC_CONTROL1_REG); } static void set_dac_select_reg(struct comedi_device *dev, const struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; uint16_t bits; unsigned int first_channel, last_channel; @@ -3366,12 +3142,18 @@ static void set_dac_select_reg(struct comedi_device *dev, bits = (first_channel & 0x7) | (last_channel & 0x7) << 3; - writew(bits, priv(dev)->main_iobase + DAC_SELECT_REG); + writew(bits, devpriv->main_iobase + DAC_SELECT_REG); +} + +static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags) +{ + return get_divisor(ns, flags) - 2; } static void set_dac_interval_regs(struct comedi_device *dev, const struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; unsigned int divisor; if (cmd->scan_begin_src != TRIG_TIMER) @@ -3383,107 +3165,39 @@ static void set_dac_interval_regs(struct comedi_device *dev, divisor = max_counter_value; } writew(divisor & 0xffff, - priv(dev)->main_iobase + DAC_SAMPLE_INTERVAL_LOWER_REG); + devpriv->main_iobase + DAC_SAMPLE_INTERVAL_LOWER_REG); writew((divisor >> 16) & 0xff, - priv(dev)->main_iobase + DAC_SAMPLE_INTERVAL_UPPER_REG); -} - -static unsigned int load_ao_dma_buffer(struct comedi_device *dev, - const struct comedi_cmd *cmd) -{ - unsigned int num_bytes, buffer_index, prev_buffer_index; - unsigned int next_bits; - - buffer_index = priv(dev)->ao_dma_index; - prev_buffer_index = prev_ao_dma_index(dev); - - DEBUG_PRINT("attempting to load ao buffer %i (0x%x)\n", buffer_index, - priv(dev)->ao_buffer_bus_addr[buffer_index]); - - num_bytes = comedi_buf_read_n_available(dev->write_subdev->async); - if (num_bytes > DMA_BUFFER_SIZE) - num_bytes = DMA_BUFFER_SIZE; - if (cmd->stop_src == TRIG_COUNT && num_bytes > priv(dev)->ao_count) - num_bytes = priv(dev)->ao_count; - num_bytes -= num_bytes % bytes_in_sample; - - if (num_bytes == 0) - return 0; - - DEBUG_PRINT("loading %i bytes\n", num_bytes); - - num_bytes = cfc_read_array_from_buffer(dev->write_subdev, - priv(dev)-> - ao_buffer[buffer_index], - num_bytes); - priv(dev)->ao_dma_desc[buffer_index].transfer_size = - cpu_to_le32(num_bytes); - /* set end of chain bit so we catch underruns */ - next_bits = le32_to_cpu(priv(dev)->ao_dma_desc[buffer_index].next); - next_bits |= PLX_END_OF_CHAIN_BIT; - priv(dev)->ao_dma_desc[buffer_index].next = cpu_to_le32(next_bits); - /* clear end of chain bit on previous buffer now that we have set it - * for the last buffer */ - next_bits = le32_to_cpu(priv(dev)->ao_dma_desc[prev_buffer_index].next); - next_bits &= ~PLX_END_OF_CHAIN_BIT; - priv(dev)->ao_dma_desc[prev_buffer_index].next = cpu_to_le32(next_bits); - - priv(dev)->ao_dma_index = (buffer_index + 1) % AO_DMA_RING_COUNT; - priv(dev)->ao_count -= num_bytes; - - return num_bytes; -} - -static void load_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) -{ - unsigned int num_bytes; - unsigned int next_transfer_addr; - void __iomem *pci_addr_reg = - priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; - unsigned int buffer_index; - - do { - buffer_index = priv(dev)->ao_dma_index; - /* don't overwrite data that hasn't been transferred yet */ - next_transfer_addr = readl(pci_addr_reg); - if (next_transfer_addr >= - priv(dev)->ao_buffer_bus_addr[buffer_index] - && next_transfer_addr < - priv(dev)->ao_buffer_bus_addr[buffer_index] + - DMA_BUFFER_SIZE) - return; - num_bytes = load_ao_dma_buffer(dev, cmd); - } while (num_bytes >= DMA_BUFFER_SIZE); + devpriv->main_iobase + DAC_SAMPLE_INTERVAL_UPPER_REG); } static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) { + struct pcidas64_private *devpriv = dev->private; unsigned int num_bytes; int i; /* clear queue pointer too, since external queue has * weird interactions with ao fifo */ - writew(0, priv(dev)->main_iobase + ADC_QUEUE_CLEAR_REG); - writew(0, priv(dev)->main_iobase + DAC_BUFFER_CLEAR_REG); + writew(0, devpriv->main_iobase + ADC_QUEUE_CLEAR_REG); + writew(0, devpriv->main_iobase + DAC_BUFFER_CLEAR_REG); num_bytes = (DAC_FIFO_SIZE / 2) * bytes_in_sample; if (cmd->stop_src == TRIG_COUNT && - num_bytes / bytes_in_sample > priv(dev)->ao_count) - num_bytes = priv(dev)->ao_count * bytes_in_sample; + num_bytes / bytes_in_sample > devpriv->ao_count) + num_bytes = devpriv->ao_count * bytes_in_sample; num_bytes = cfc_read_array_from_buffer(dev->write_subdev, - priv(dev)->ao_bounce_buffer, + devpriv->ao_bounce_buffer, num_bytes); for (i = 0; i < num_bytes / bytes_in_sample; i++) { - writew(priv(dev)->ao_bounce_buffer[i], - priv(dev)->main_iobase + DAC_FIFO_REG); + writew(devpriv->ao_bounce_buffer[i], + devpriv->main_iobase + DAC_FIFO_REG); } - priv(dev)->ao_count -= num_bytes / bytes_in_sample; - if (cmd->stop_src == TRIG_COUNT && priv(dev)->ao_count == 0) + devpriv->ao_count -= num_bytes / bytes_in_sample; + if (cmd->stop_src == TRIG_COUNT && devpriv->ao_count == 0) return 0; num_bytes = load_ao_dma_buffer(dev, cmd); if (num_bytes == 0) return -1; - if (num_bytes >= DMA_BUFFER_SIZE) ; load_ao_dma(dev, cmd); dma_start_sync(dev, 0); @@ -3491,34 +3205,63 @@ static int prep_ao_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) return 0; } -static inline int external_ai_queue_in_use(struct comedi_device *dev) +static inline int external_ai_queue_in_use(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - if (dev->read_subdev->busy) + const struct pcidas64_board *thisboard = comedi_board(dev); + + if (s->busy) return 0; - if (board(dev)->layout == LAYOUT_4020) + if (thisboard->layout == LAYOUT_4020) return 0; - else if (use_internal_queue_6xxx(&dev->read_subdev->async->cmd)) + else if (use_internal_queue_6xxx(cmd)) return 0; return 1; } +static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, + unsigned int trig_num) +{ + struct pcidas64_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int retval; + + if (trig_num != cmd->start_arg) + return -EINVAL; + + retval = prep_ao_dma(dev, cmd); + if (retval < 0) + return -EPIPE; + + set_dac_control0_reg(dev, cmd); + + if (cmd->start_src == TRIG_INT) + writew(0, devpriv->main_iobase + DAC_START_REG); + + s->async->inttrig = NULL; + + return 0; +} + static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcidas64_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - if (external_ai_queue_in_use(dev)) { + if (external_ai_queue_in_use(dev, s, cmd)) { warn_external_queue(dev); return -EBUSY; } /* disable analog output system during setup */ - writew(0x0, priv(dev)->main_iobase + DAC_CONTROL0_REG); + writew(0x0, devpriv->main_iobase + DAC_CONTROL0_REG); - priv(dev)->ao_dma_index = 0; - priv(dev)->ao_count = cmd->stop_arg * cmd->chanlist_len; + devpriv->ao_dma_index = 0; + devpriv->ao_count = cmd->stop_arg * cmd->chanlist_len; set_dac_select_reg(dev, cmd); set_dac_interval_regs(dev, cmd); - load_first_dma_descriptor(dev, 0, priv(dev)->ao_dma_desc_bus_addr | + load_first_dma_descriptor(dev, 0, devpriv->ao_dma_desc_bus_addr | PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT); set_dac_control1_reg(dev, cmd); @@ -3527,25 +3270,22 @@ static int ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trig_num) +static int cb_pcidas64_ao_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - struct comedi_cmd *cmd = &s->async->cmd; - int retval; - - if (trig_num != 0) - return -EINVAL; - - retval = prep_ao_dma(dev, cmd); - if (retval < 0) - return -EPIPE; - - set_dac_control0_reg(dev, cmd); + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + int i; - if (cmd->start_src == TRIG_INT) - writew(0, priv(dev)->main_iobase + DAC_START_REG); + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); - s->async->inttrig = NULL; + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "chanlist must use consecutive channels\n"); + return -EINVAL; + } + } return 0; } @@ -3553,83 +3293,55 @@ static int ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct pcidas64_board *thisboard = comedi_board(dev); int err = 0; - int tmp; unsigned int tmp_arg; - int i; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* 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); - /* uniqueness check */ - if (cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; + /* Step 2b : and mutually compatible */ - /* compatibility check */ if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) - err++; + err |= -EINVAL; if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err++; + err |= -EINVAL; if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < board(dev)->ao_scan_speed) { - cmd->scan_begin_arg = board(dev)->ao_scan_speed; - err++; - } - if (get_ao_divisor(cmd->scan_begin_arg, - cmd->flags) > max_counter_value) { - cmd->scan_begin_arg = - (max_counter_value + 2) * TIMER_BASE; - err++; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + thisboard->ao_scan_speed); + if (get_ao_divisor(cmd->scan_begin_arg, cmd->flags) > + max_counter_value) { + cmd->scan_begin_arg = (max_counter_value + 2) * + TIMER_BASE; + err |= -EINVAL; } } - if (!cmd->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (err) return 3; @@ -3638,8 +3350,8 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->scan_begin_src == TRIG_TIMER) { tmp_arg = cmd->scan_begin_arg; - cmd->scan_begin_arg = - get_divisor(cmd->scan_begin_arg, cmd->flags) * TIMER_BASE; + cmd->scan_begin_arg = get_divisor(cmd->scan_begin_arg, + cmd->flags) * TIMER_BASE; if (tmp_arg != cmd->scan_begin_arg) err++; } @@ -3647,17 +3359,9 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - if (cmd->chanlist) { - unsigned int first_channel = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != first_channel + i) { - comedi_error(dev, - "chanlist must use consecutive channels"); - err++; - break; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= cb_pcidas64_ao_check_chanlist(dev, s, cmd); if (err) return 5; @@ -3667,7 +3371,9 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, static int ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - writew(0x0, priv(dev)->main_iobase + DAC_CONTROL0_REG); + struct pcidas64_private *devpriv = dev->private; + + writew(0x0, devpriv->main_iobase + DAC_CONTROL0_REG); abort_dma(dev, 0); return 0; } @@ -3677,7 +3383,6 @@ static int dio_callback(int dir, int port, int data, unsigned long arg) void __iomem *iobase = (void __iomem *)arg; if (dir) { writeb(data, iobase + port); - DEBUG_PRINT("wrote 0x%x to port %i\n", data, port); return 0; } else { return readb(iobase + port); @@ -3698,81 +3403,190 @@ static int dio_callback_4020(int dir, int port, int data, unsigned long arg) static int di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pcidas64_private *devpriv = dev->private; unsigned int bits; - bits = readb(priv(dev)->dio_counter_iobase + DI_REG); + bits = readb(devpriv->dio_counter_iobase + DI_REG); bits &= 0xf; data[1] = bits; data[0] = 0; - return 2; + return insn->n; } -static int do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int do_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - data[0] &= 0xf; - /* zero bits we are going to change */ - s->state &= ~data[0]; - /* set new bits */ - s->state |= data[0] & data[1]; + struct pcidas64_private *devpriv = dev->private; - writeb(s->state, priv(dev)->dio_counter_iobase + DO_REG); + if (comedi_dio_update_state(s, data)) + writeb(s->state, devpriv->dio_counter_iobase + DO_REG); data[1] = s->state; - return 2; + return insn->n; } static int dio_60xx_config_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int mask; - - mask = 1 << CR_CHAN(insn->chanspec); + struct pcidas64_private *devpriv = dev->private; + int ret; - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - return 2; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; writeb(s->io_bits, - priv(dev)->dio_counter_iobase + DIO_DIRECTION_60XX_REG); + devpriv->dio_counter_iobase + DIO_DIRECTION_60XX_REG); - return 1; + return insn->n; } -static int dio_60xx_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int dio_60xx_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + struct pcidas64_private *devpriv = dev->private; + + if (comedi_dio_update_state(s, data)) { writeb(s->state, - priv(dev)->dio_counter_iobase + DIO_DATA_60XX_REG); + devpriv->dio_counter_iobase + DIO_DATA_60XX_REG); } - data[1] = readb(priv(dev)->dio_counter_iobase + DIO_DATA_60XX_REG); + data[1] = readb(devpriv->dio_counter_iobase + DIO_DATA_60XX_REG); - return 2; + return insn->n; +} + +/* pci-6025 8800 caldac: + * address 0 == dac channel 0 offset + * address 1 == dac channel 0 gain + * address 2 == dac channel 1 offset + * address 3 == dac channel 1 gain + * address 4 == fine adc offset + * address 5 == coarse adc offset + * address 6 == coarse adc gain + * address 7 == fine adc gain + */ +/* pci-6402/16 uses all 8 channels for dac: + * address 0 == dac channel 0 fine gain + * address 1 == dac channel 0 coarse gain + * address 2 == dac channel 0 coarse offset + * address 3 == dac channel 1 coarse offset + * address 4 == dac channel 1 fine gain + * address 5 == dac channel 1 coarse gain + * address 6 == dac channel 0 fine offset + * address 7 == dac channel 1 fine offset +*/ + +static int caldac_8800_write(struct comedi_device *dev, unsigned int address, + uint8_t value) +{ + struct pcidas64_private *devpriv = dev->private; + static const int num_caldac_channels = 8; + static const int bitstream_length = 11; + unsigned int bitstream = ((address & 0x7) << 8) | value; + unsigned int bit, register_bits; + static const int caldac_8800_udelay = 1; + + if (address >= num_caldac_channels) { + comedi_error(dev, "illegal caldac channel"); + return -1; + } + for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { + register_bits = 0; + if (bitstream & bit) + register_bits |= SERIAL_DATA_IN_BIT; + udelay(caldac_8800_udelay); + writew(register_bits, devpriv->main_iobase + CALIBRATION_REG); + register_bits |= SERIAL_CLOCK_BIT; + udelay(caldac_8800_udelay); + writew(register_bits, devpriv->main_iobase + CALIBRATION_REG); + } + udelay(caldac_8800_udelay); + writew(SELECT_8800_BIT, devpriv->main_iobase + CALIBRATION_REG); + udelay(caldac_8800_udelay); + writew(0, devpriv->main_iobase + CALIBRATION_REG); + udelay(caldac_8800_udelay); + return 0; +} + +/* 4020 caldacs */ +static int caldac_i2c_write(struct comedi_device *dev, + unsigned int caldac_channel, unsigned int value) +{ + uint8_t serial_bytes[3]; + uint8_t i2c_addr; + enum pointer_bits { + /* manual has gain and offset bits switched */ + OFFSET_0_2 = 0x1, + GAIN_0_2 = 0x2, + OFFSET_1_3 = 0x4, + GAIN_1_3 = 0x8, + }; + enum data_bits { + NOT_CLEAR_REGISTERS = 0x20, + }; + + switch (caldac_channel) { + case 0: /* chan 0 offset */ + i2c_addr = CALDAC0_I2C_ADDR; + serial_bytes[0] = OFFSET_0_2; + break; + case 1: /* chan 1 offset */ + i2c_addr = CALDAC0_I2C_ADDR; + serial_bytes[0] = OFFSET_1_3; + break; + case 2: /* chan 2 offset */ + i2c_addr = CALDAC1_I2C_ADDR; + serial_bytes[0] = OFFSET_0_2; + break; + case 3: /* chan 3 offset */ + i2c_addr = CALDAC1_I2C_ADDR; + serial_bytes[0] = OFFSET_1_3; + break; + case 4: /* chan 0 gain */ + i2c_addr = CALDAC0_I2C_ADDR; + serial_bytes[0] = GAIN_0_2; + break; + case 5: /* chan 1 gain */ + i2c_addr = CALDAC0_I2C_ADDR; + serial_bytes[0] = GAIN_1_3; + break; + case 6: /* chan 2 gain */ + i2c_addr = CALDAC1_I2C_ADDR; + serial_bytes[0] = GAIN_0_2; + break; + case 7: /* chan 3 gain */ + i2c_addr = CALDAC1_I2C_ADDR; + serial_bytes[0] = GAIN_1_3; + break; + default: + comedi_error(dev, "invalid caldac channel\n"); + return -1; + break; + } + serial_bytes[1] = NOT_CLEAR_REGISTERS | ((value >> 8) & 0xf); + serial_bytes[2] = value & 0xff; + i2c_write(dev, i2c_addr, serial_bytes, 3); + return 0; } static void caldac_write(struct comedi_device *dev, unsigned int channel, unsigned int value) { - priv(dev)->caldac_state[channel] = value; + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + + devpriv->caldac_state[channel] = value; - switch (board(dev)->layout) { + switch (thisboard->layout) { case LAYOUT_60XX: case LAYOUT_64XX: caldac_8800_write(dev, channel, value); @@ -3789,11 +3603,12 @@ static int calib_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pcidas64_private *devpriv = dev->private; int channel = CR_CHAN(insn->chanspec); /* return immediately if setting hasn't changed, since * programming these things is slow */ - if (priv(dev)->caldac_state[channel] == data[0]) + if (devpriv->caldac_state[channel] == data[0]) return 1; caldac_write(dev, channel, data[0]); @@ -3805,9 +3620,10 @@ static int calib_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pcidas64_private *devpriv = dev->private; unsigned int channel = CR_CHAN(insn->chanspec); - data[0] = priv(dev)->caldac_state[channel]; + data[0] = devpriv->caldac_state[channel]; return 1; } @@ -3815,16 +3631,17 @@ static int calib_read_insn(struct comedi_device *dev, static void ad8402_write(struct comedi_device *dev, unsigned int channel, unsigned int value) { + struct pcidas64_private *devpriv = dev->private; static const int bitstream_length = 10; unsigned int bit, register_bits; unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff); static const int ad8402_udelay = 1; - priv(dev)->ad8402_state[channel] = value; + devpriv->ad8402_state[channel] = value; register_bits = SELECT_8402_64XX_BIT; udelay(ad8402_udelay); - writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG); + writew(register_bits, devpriv->main_iobase + CALIBRATION_REG); for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { if (bitstream & bit) @@ -3832,14 +3649,14 @@ static void ad8402_write(struct comedi_device *dev, unsigned int channel, else register_bits &= ~SERIAL_DATA_IN_BIT; udelay(ad8402_udelay); - writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG); + writew(register_bits, devpriv->main_iobase + CALIBRATION_REG); udelay(ad8402_udelay); writew(register_bits | SERIAL_CLOCK_BIT, - priv(dev)->main_iobase + CALIBRATION_REG); + devpriv->main_iobase + CALIBRATION_REG); } udelay(ad8402_udelay); - writew(0, priv(dev)->main_iobase + CALIBRATION_REG); + writew(0, devpriv->main_iobase + CALIBRATION_REG); } /* for pci-das6402/16, channel 0 is analog input gain and channel 1 is offset */ @@ -3847,14 +3664,15 @@ static int ad8402_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pcidas64_private *devpriv = dev->private; int channel = CR_CHAN(insn->chanspec); /* return immediately if setting hasn't changed, since * programming these things is slow */ - if (priv(dev)->ad8402_state[channel] == data[0]) + if (devpriv->ad8402_state[channel] == data[0]) return 1; - priv(dev)->ad8402_state[channel] = data[0]; + devpriv->ad8402_state[channel] = data[0]; ad8402_write(dev, channel, data[0]); @@ -3865,62 +3683,64 @@ static int ad8402_read_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pcidas64_private *devpriv = dev->private; unsigned int channel = CR_CHAN(insn->chanspec); - data[0] = priv(dev)->ad8402_state[channel]; + data[0] = devpriv->ad8402_state[channel]; return 1; } static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address) { + struct pcidas64_private *devpriv = dev->private; static const int bitstream_length = 11; static const int read_command = 0x6; unsigned int bitstream = (read_command << 8) | address; unsigned int bit; void __iomem * const plx_control_addr = - priv(dev)->plx9080_iobase + PLX_CONTROL_REG; + devpriv->plx9080_iobase + PLX_CONTROL_REG; uint16_t value; static const int value_length = 16; static const int eeprom_udelay = 1; udelay(eeprom_udelay); - priv(dev)->plx_control_bits &= ~CTL_EE_CLK & ~CTL_EE_CS; + devpriv->plx_control_bits &= ~CTL_EE_CLK & ~CTL_EE_CS; /* make sure we don't send anything to the i2c bus on 4020 */ - priv(dev)->plx_control_bits |= CTL_USERO; - writel(priv(dev)->plx_control_bits, plx_control_addr); + devpriv->plx_control_bits |= CTL_USERO; + writel(devpriv->plx_control_bits, plx_control_addr); /* activate serial eeprom */ udelay(eeprom_udelay); - priv(dev)->plx_control_bits |= CTL_EE_CS; - writel(priv(dev)->plx_control_bits, plx_control_addr); + devpriv->plx_control_bits |= CTL_EE_CS; + writel(devpriv->plx_control_bits, plx_control_addr); /* write read command and desired memory address */ for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { /* set bit to be written */ udelay(eeprom_udelay); if (bitstream & bit) - priv(dev)->plx_control_bits |= CTL_EE_W; + devpriv->plx_control_bits |= CTL_EE_W; else - priv(dev)->plx_control_bits &= ~CTL_EE_W; - writel(priv(dev)->plx_control_bits, plx_control_addr); + devpriv->plx_control_bits &= ~CTL_EE_W; + writel(devpriv->plx_control_bits, plx_control_addr); /* clock in bit */ udelay(eeprom_udelay); - priv(dev)->plx_control_bits |= CTL_EE_CLK; - writel(priv(dev)->plx_control_bits, plx_control_addr); + devpriv->plx_control_bits |= CTL_EE_CLK; + writel(devpriv->plx_control_bits, plx_control_addr); udelay(eeprom_udelay); - priv(dev)->plx_control_bits &= ~CTL_EE_CLK; - writel(priv(dev)->plx_control_bits, plx_control_addr); + devpriv->plx_control_bits &= ~CTL_EE_CLK; + writel(devpriv->plx_control_bits, plx_control_addr); } /* read back value from eeprom memory location */ value = 0; for (bit = 1 << (value_length - 1); bit; bit >>= 1) { /* clock out bit */ udelay(eeprom_udelay); - priv(dev)->plx_control_bits |= CTL_EE_CLK; - writel(priv(dev)->plx_control_bits, plx_control_addr); + devpriv->plx_control_bits |= CTL_EE_CLK; + writel(devpriv->plx_control_bits, plx_control_addr); udelay(eeprom_udelay); - priv(dev)->plx_control_bits &= ~CTL_EE_CLK; - writel(priv(dev)->plx_control_bits, plx_control_addr); + devpriv->plx_control_bits &= ~CTL_EE_CLK; + writel(devpriv->plx_control_bits, plx_control_addr); udelay(eeprom_udelay); if (readl(plx_control_addr) & CTL_EE_R) value |= bit; @@ -3928,8 +3748,8 @@ static uint16_t read_eeprom(struct comedi_device *dev, uint8_t address) /* deactivate eeprom serial input */ udelay(eeprom_udelay); - priv(dev)->plx_control_bits &= ~CTL_EE_CS; - writel(priv(dev)->plx_control_bits, plx_control_addr); + devpriv->plx_control_bits &= ~CTL_EE_CS; + writel(devpriv->plx_control_bits, plx_control_addr); return value; } @@ -3943,380 +3763,356 @@ static int eeprom_read_insn(struct comedi_device *dev, return 1; } -/* utility function that rounds desired timing to an achievable time, and - * sets cmd members appropriately. - * adc paces conversions from master clock by dividing by (x + 3) where x is 24 bit number +/* Allocate and initialize the subdevice structures. */ -static void check_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) +static int setup_subdevices(struct comedi_device *dev) { - unsigned int convert_divisor = 0, scan_divisor; - static const int min_convert_divisor = 3; - static const int max_convert_divisor = - max_counter_value + min_convert_divisor; - static const int min_scan_divisor_4020 = 2; - unsigned long long max_scan_divisor, min_scan_divisor; + const struct pcidas64_board *thisboard = comedi_board(dev); + struct pcidas64_private *devpriv = dev->private; + struct comedi_subdevice *s; + void __iomem *dio_8255_iobase; + int i; + int ret; - if (cmd->convert_src == TRIG_TIMER) { - if (board(dev)->layout == LAYOUT_4020) { - cmd->convert_arg = 0; - } else { - convert_divisor = - get_divisor(cmd->convert_arg, cmd->flags); - if (convert_divisor > max_convert_divisor) - convert_divisor = max_convert_divisor; - if (convert_divisor < min_convert_divisor) - convert_divisor = min_convert_divisor; - cmd->convert_arg = convert_divisor * TIMER_BASE; - } - } else if (cmd->convert_src == TRIG_NOW) - cmd->convert_arg = 0; + ret = comedi_alloc_subdevices(dev, 10); + if (ret) + return ret; - if (cmd->scan_begin_src == TRIG_TIMER) { - scan_divisor = get_divisor(cmd->scan_begin_arg, cmd->flags); - if (cmd->convert_src == TRIG_TIMER) { - /* XXX check for integer overflows */ - min_scan_divisor = convert_divisor * cmd->chanlist_len; - max_scan_divisor = - (convert_divisor * cmd->chanlist_len - 1) + - max_counter_value; - } else { - min_scan_divisor = min_scan_divisor_4020; - max_scan_divisor = max_counter_value + min_scan_divisor; + s = &dev->subdevices[0]; + /* analog input subdevice */ + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DITHER | SDF_CMD_READ; + if (thisboard->layout == LAYOUT_60XX) + s->subdev_flags |= SDF_COMMON | SDF_DIFF; + else if (thisboard->layout == LAYOUT_64XX) + s->subdev_flags |= SDF_DIFF; + /* XXX Number of inputs in differential mode is ignored */ + s->n_chan = thisboard->ai_se_chans; + s->len_chanlist = 0x2000; + s->maxdata = (1 << thisboard->ai_bits) - 1; + s->range_table = thisboard->ai_range_table; + s->insn_read = ai_rinsn; + s->insn_config = ai_config_insn; + s->do_cmd = ai_cmd; + s->do_cmdtest = ai_cmdtest; + s->cancel = ai_cancel; + if (thisboard->layout == LAYOUT_4020) { + uint8_t data; + /* set adc to read from inputs + * (not internal calibration sources) */ + devpriv->i2c_cal_range_bits = adc_src_4020_bits(4); + /* set channels to +-5 volt input ranges */ + for (i = 0; i < s->n_chan; i++) + devpriv->i2c_cal_range_bits |= attenuate_bit(i); + data = devpriv->i2c_cal_range_bits; + i2c_write(dev, RANGE_CAL_I2C_ADDR, &data, sizeof(data)); + } + + /* analog output subdevice */ + s = &dev->subdevices[1]; + if (thisboard->ao_nchan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | + SDF_GROUND | SDF_CMD_WRITE; + 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; + if (ao_cmd_is_supported(thisboard)) { + dev->write_subdev = s; + s->do_cmdtest = ao_cmdtest; + s->do_cmd = ao_cmd; + s->len_chanlist = thisboard->ao_nchan; + s->cancel = ao_cancel; } - if (scan_divisor > max_scan_divisor) - scan_divisor = max_scan_divisor; - if (scan_divisor < min_scan_divisor) - scan_divisor = min_scan_divisor; - cmd->scan_begin_arg = scan_divisor * TIMER_BASE; + } else { + s->type = COMEDI_SUBD_UNUSED; } - return; -} + /* digital input */ + s = &dev->subdevices[2]; + if (thisboard->layout == LAYOUT_64XX) { + 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 = di_rbits; + } else + s->type = COMEDI_SUBD_UNUSED; -/* Gets nearest achievable timing given master clock speed, does not - * take into account possible minimum/maximum divisor values. Used - * by other timing checking functions. */ -static unsigned int get_divisor(unsigned int ns, unsigned int flags) -{ - unsigned int divisor; + /* digital output */ + if (thisboard->layout == LAYOUT_64XX) { + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = do_wbits; + } else + s->type = COMEDI_SUBD_UNUSED; - switch (flags & TRIG_ROUND_MASK) { - case TRIG_ROUND_UP: - divisor = (ns + TIMER_BASE - 1) / TIMER_BASE; - break; - case TRIG_ROUND_DOWN: - divisor = ns / TIMER_BASE; - break; - case TRIG_ROUND_NEAREST: - default: - divisor = (ns + TIMER_BASE / 2) / TIMER_BASE; - break; + /* 8255 */ + 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); + } else { + dio_8255_iobase = + devpriv->dio_counter_iobase + DIO_8255_OFFSET; + ret = subdev_8255_init(dev, s, dio_callback, + (unsigned long)dio_8255_iobase); + } + if (ret) + return ret; + } else { + s->type = COMEDI_SUBD_UNUSED; } - return divisor; -} - -static unsigned int get_ao_divisor(unsigned int ns, unsigned int flags) -{ - return get_divisor(ns, flags) - 2; -} -/* 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) -{ - unsigned int num_fifo_entries; - int retval; - const struct hw_fifo_info *const fifo = board(dev)->ai_fifo; + /* 8 channel dio for 60xx */ + s = &dev->subdevices[5]; + if (thisboard->layout == LAYOUT_60XX) { + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = dio_60xx_config_insn; + s->insn_bits = dio_60xx_wbits; + } else + s->type = COMEDI_SUBD_UNUSED; - num_fifo_entries = num_samples / fifo->sample_packing_ratio; + /* caldac */ + s = &dev->subdevices[6]; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 8; + if (thisboard->layout == LAYOUT_4020) + s->maxdata = 0xfff; + else + s->maxdata = 0xff; + s->insn_read = calib_read_insn; + s->insn_write = calib_write_insn; + for (i = 0; i < s->n_chan; i++) + caldac_write(dev, i, s->maxdata / 2); - retval = set_ai_fifo_segment_length(dev, - num_fifo_entries / - fifo->num_segments); - if (retval < 0) - return retval; + /* 2 channel ad8402 potentiometer */ + s = &dev->subdevices[7]; + if (thisboard->layout == LAYOUT_64XX) { + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = 2; + s->insn_read = ad8402_read_insn; + s->insn_write = ad8402_write_insn; + s->maxdata = 0xff; + for (i = 0; i < s->n_chan; i++) + ad8402_write(dev, i, s->maxdata / 2); + } else + s->type = COMEDI_SUBD_UNUSED; - num_samples = retval * fifo->num_segments * fifo->sample_packing_ratio; + /* serial EEPROM, if present */ + s = &dev->subdevices[8]; + if (readl(devpriv->plx9080_iobase + PLX_CONTROL_REG) & CTL_EECHK) { + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE | SDF_INTERNAL; + s->n_chan = 128; + s->maxdata = 0xffff; + s->insn_read = eeprom_read_insn; + } else + s->type = COMEDI_SUBD_UNUSED; - DEBUG_PRINT("set hardware fifo size to %i\n", num_samples); + /* user counter subd XXX */ + s = &dev->subdevices[9]; + s->type = COMEDI_SUBD_UNUSED; - return num_samples; + return 0; } -/* query length of fifo */ -static unsigned int ai_fifo_size(struct comedi_device *dev) +static int auto_attach(struct comedi_device *dev, + unsigned long context) { - return priv(dev)->ai_fifo_segment_length * - board(dev)->ai_fifo->num_segments * - board(dev)->ai_fifo->sample_packing_ratio; -} - -static int set_ai_fifo_segment_length(struct comedi_device *dev, - unsigned int num_entries) -{ - static const int increment_size = 0x100; - const struct hw_fifo_info *const fifo = board(dev)->ai_fifo; - unsigned int num_increments; - uint16_t bits; - - if (num_entries < increment_size) - num_entries = increment_size; - if (num_entries > fifo->max_segment_length) - num_entries = fifo->max_segment_length; - - /* 1 == 256 entries, 2 == 512 entries, etc */ - num_increments = (num_entries + increment_size / 2) / increment_size; - - bits = (~(num_increments - 1)) & fifo->fifo_size_reg_mask; - priv(dev)->fifo_size_bits &= ~fifo->fifo_size_reg_mask; - priv(dev)->fifo_size_bits |= bits; - writew(priv(dev)->fifo_size_bits, - priv(dev)->main_iobase + FIFO_SIZE_REG); - - priv(dev)->ai_fifo_segment_length = num_increments * increment_size; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct pcidas64_board *thisboard = NULL; + struct pcidas64_private *devpriv; + uint32_t local_range, local_decode; + int retval; - DEBUG_PRINT("set hardware fifo segment length to %i\n", - priv(dev)->ai_fifo_segment_length); + if (context < ARRAY_SIZE(pcidas64_boards)) + thisboard = &pcidas64_boards[context]; + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; - return priv(dev)->ai_fifo_segment_length; -} + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; -/* pci-6025 8800 caldac: - * address 0 == dac channel 0 offset - * address 1 == dac channel 0 gain - * address 2 == dac channel 1 offset - * address 3 == dac channel 1 gain - * address 4 == fine adc offset - * address 5 == coarse adc offset - * address 6 == coarse adc gain - * address 7 == fine adc gain - */ -/* pci-6402/16 uses all 8 channels for dac: - * address 0 == dac channel 0 fine gain - * address 1 == dac channel 0 coarse gain - * address 2 == dac channel 0 coarse offset - * address 3 == dac channel 1 coarse offset - * address 4 == dac channel 1 fine gain - * address 5 == dac channel 1 coarse gain - * address 6 == dac channel 0 fine offset - * address 7 == dac channel 1 fine offset -*/ + retval = comedi_pci_enable(dev); + if (retval) + return retval; + pci_set_master(pcidev); -static int caldac_8800_write(struct comedi_device *dev, unsigned int address, - uint8_t value) -{ - static const int num_caldac_channels = 8; - static const int bitstream_length = 11; - unsigned int bitstream = ((address & 0x7) << 8) | value; - unsigned int bit, register_bits; - static const int caldac_8800_udelay = 1; + /* Initialize dev->board_name */ + dev->board_name = thisboard->name; - if (address >= num_caldac_channels) { - comedi_error(dev, "illegal caldac channel"); - return -1; - } - for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) { - register_bits = 0; - if (bitstream & bit) - register_bits |= SERIAL_DATA_IN_BIT; - udelay(caldac_8800_udelay); - writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG); - register_bits |= SERIAL_CLOCK_BIT; - udelay(caldac_8800_udelay); - writew(register_bits, priv(dev)->main_iobase + CALIBRATION_REG); - } - udelay(caldac_8800_udelay); - writew(SELECT_8800_BIT, priv(dev)->main_iobase + CALIBRATION_REG); - udelay(caldac_8800_udelay); - writew(0, priv(dev)->main_iobase + CALIBRATION_REG); - udelay(caldac_8800_udelay); - return 0; -} + devpriv->main_phys_iobase = pci_resource_start(pcidev, 2); + devpriv->dio_counter_phys_iobase = pci_resource_start(pcidev, 3); -/* 4020 caldacs */ -static int caldac_i2c_write(struct comedi_device *dev, - unsigned int caldac_channel, unsigned int value) -{ - uint8_t serial_bytes[3]; - uint8_t i2c_addr; - enum pointer_bits { - /* manual has gain and offset bits switched */ - OFFSET_0_2 = 0x1, - GAIN_0_2 = 0x2, - OFFSET_1_3 = 0x4, - GAIN_1_3 = 0x8, - }; - enum data_bits { - NOT_CLEAR_REGISTERS = 0x20, - }; + devpriv->plx9080_iobase = pci_ioremap_bar(pcidev, 0); + devpriv->main_iobase = pci_ioremap_bar(pcidev, 2); + devpriv->dio_counter_iobase = pci_ioremap_bar(pcidev, 3); - switch (caldac_channel) { - case 0: /* chan 0 offset */ - i2c_addr = CALDAC0_I2C_ADDR; - serial_bytes[0] = OFFSET_0_2; - break; - case 1: /* chan 1 offset */ - i2c_addr = CALDAC0_I2C_ADDR; - serial_bytes[0] = OFFSET_1_3; - break; - case 2: /* chan 2 offset */ - i2c_addr = CALDAC1_I2C_ADDR; - serial_bytes[0] = OFFSET_0_2; - break; - case 3: /* chan 3 offset */ - i2c_addr = CALDAC1_I2C_ADDR; - serial_bytes[0] = OFFSET_1_3; - break; - case 4: /* chan 0 gain */ - i2c_addr = CALDAC0_I2C_ADDR; - serial_bytes[0] = GAIN_0_2; - break; - case 5: /* chan 1 gain */ - i2c_addr = CALDAC0_I2C_ADDR; - serial_bytes[0] = GAIN_1_3; - break; - case 6: /* chan 2 gain */ - i2c_addr = CALDAC1_I2C_ADDR; - serial_bytes[0] = GAIN_0_2; - break; - case 7: /* chan 3 gain */ - i2c_addr = CALDAC1_I2C_ADDR; - serial_bytes[0] = GAIN_1_3; - break; - default: - comedi_error(dev, "invalid caldac channel\n"); - return -1; - break; + if (!devpriv->plx9080_iobase || !devpriv->main_iobase + || !devpriv->dio_counter_iobase) { + dev_warn(dev->class_dev, "failed to remap io memory\n"); + return -ENOMEM; } - serial_bytes[1] = NOT_CLEAR_REGISTERS | ((value >> 8) & 0xf); - serial_bytes[2] = value & 0xff; - i2c_write(dev, i2c_addr, serial_bytes, 3); - return 0; -} - -/* Their i2c requires a huge delay on setting clock or data high for some reason */ -static const int i2c_high_udelay = 1000; -static const int i2c_low_udelay = 10; -/* set i2c data line high or low */ -static void i2c_set_sda(struct comedi_device *dev, int state) -{ - static const int data_bit = CTL_EE_W; - void __iomem *plx_control_addr = priv(dev)->plx9080_iobase + - PLX_CONTROL_REG; + /* figure out what local addresses are */ + local_range = readl(devpriv->plx9080_iobase + PLX_LAS0RNG_REG) & + LRNG_MEM_MASK; + local_decode = readl(devpriv->plx9080_iobase + PLX_LAS0MAP_REG) & + local_range & LMAP_MEM_MASK; + devpriv->local0_iobase = ((uint32_t)devpriv->main_phys_iobase & + ~local_range) | local_decode; + local_range = readl(devpriv->plx9080_iobase + PLX_LAS1RNG_REG) & + LRNG_MEM_MASK; + local_decode = readl(devpriv->plx9080_iobase + PLX_LAS1MAP_REG) & + local_range & LMAP_MEM_MASK; + devpriv->local1_iobase = ((uint32_t)devpriv->dio_counter_phys_iobase & + ~local_range) | local_decode; - if (state) { - /* set data line high */ - priv(dev)->plx_control_bits &= ~data_bit; - writel(priv(dev)->plx_control_bits, plx_control_addr); - udelay(i2c_high_udelay); - } else { /* set data line low */ + retval = alloc_and_init_dma_members(dev); + if (retval < 0) + return retval; - priv(dev)->plx_control_bits |= data_bit; - writel(priv(dev)->plx_control_bits, plx_control_addr); - udelay(i2c_low_udelay); + devpriv->hw_revision = + hw_revision(dev, readw(devpriv->main_iobase + HW_STATUS_REG)); + dev_dbg(dev->class_dev, "stc hardware revision %i\n", + devpriv->hw_revision); + init_plx9080(dev); + init_stc_registers(dev); + /* get irq */ + if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, + "cb_pcidas64", dev)) { + dev_dbg(dev->class_dev, "unable to allocate irq %u\n", + pcidev->irq); + return -EINVAL; } -} - -/* set i2c clock line high or low */ -static void i2c_set_scl(struct comedi_device *dev, int state) -{ - static const int clock_bit = CTL_USERO; - void __iomem *plx_control_addr = priv(dev)->plx9080_iobase + - PLX_CONTROL_REG; + dev->irq = pcidev->irq; + dev_dbg(dev->class_dev, "irq %u\n", dev->irq); - if (state) { - /* set clock line high */ - priv(dev)->plx_control_bits &= ~clock_bit; - writel(priv(dev)->plx_control_bits, plx_control_addr); - udelay(i2c_high_udelay); - } else { /* set clock line low */ + retval = setup_subdevices(dev); + if (retval < 0) + return retval; - priv(dev)->plx_control_bits |= clock_bit; - writel(priv(dev)->plx_control_bits, plx_control_addr); - udelay(i2c_low_udelay); - } + return 0; } -static void i2c_write_byte(struct comedi_device *dev, uint8_t byte) +static void detach(struct comedi_device *dev) { - uint8_t bit; - unsigned int num_bits = 8; - - DEBUG_PRINT("writing to i2c byte 0x%x\n", byte); + 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; - for (bit = 1 << (num_bits - 1); bit; bit >>= 1) { - i2c_set_scl(dev, 0); - if ((byte & bit)) - i2c_set_sda(dev, 1); - else - i2c_set_sda(dev, 0); - i2c_set_scl(dev, 1); + 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 (devpriv->dio_counter_iobase) + iounmap(devpriv->dio_counter_iobase); + /* 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); + } } + comedi_pci_disable(dev); } -/* we can't really read the lines, so fake it */ -static int i2c_read_ack(struct comedi_device *dev) -{ - i2c_set_scl(dev, 0); - i2c_set_sda(dev, 1); - i2c_set_scl(dev, 1); - - return 0; /* return fake acknowledge bit */ -} +static struct comedi_driver cb_pcidas64_driver = { + .driver_name = "cb_pcidas64", + .module = THIS_MODULE, + .auto_attach = auto_attach, + .detach = detach, +}; -/* send start bit */ -static void i2c_start(struct comedi_device *dev) +static int cb_pcidas64_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - i2c_set_scl(dev, 1); - i2c_set_sda(dev, 1); - i2c_set_sda(dev, 0); + return comedi_pci_auto_config(dev, &cb_pcidas64_driver, + id->driver_data); } -/* send stop bit */ -static void i2c_stop(struct comedi_device *dev) -{ - i2c_set_scl(dev, 0); - i2c_set_sda(dev, 0); - i2c_set_scl(dev, 1); - i2c_set_sda(dev, 1); -} - -static void i2c_write(struct comedi_device *dev, unsigned int address, - const uint8_t * data, unsigned int length) -{ - unsigned int i; - uint8_t bitstream; - static const int read_bit = 0x1; - -/* XXX need mutex to prevent simultaneous attempts to access eeprom and i2c bus */ - - /* make sure we dont send anything to eeprom */ - priv(dev)->plx_control_bits &= ~CTL_EE_CS; - - i2c_stop(dev); - i2c_start(dev); - - /* send address and write bit */ - bitstream = (address << 1) & ~read_bit; - i2c_write_byte(dev, bitstream); +static const struct pci_device_id cb_pcidas64_pci_table[] = { + { PCI_VDEVICE(CB, 0x001d), BOARD_PCIDAS6402_16 }, + { PCI_VDEVICE(CB, 0x001e), BOARD_PCIDAS6402_12 }, + { PCI_VDEVICE(CB, 0x0035), BOARD_PCIDAS64_M1_16 }, + { PCI_VDEVICE(CB, 0x0036), BOARD_PCIDAS64_M2_16 }, + { PCI_VDEVICE(CB, 0x0037), BOARD_PCIDAS64_M3_16 }, + { PCI_VDEVICE(CB, 0x0052), BOARD_PCIDAS4020_12 }, + { PCI_VDEVICE(CB, 0x005d), BOARD_PCIDAS6023 }, + { PCI_VDEVICE(CB, 0x005e), BOARD_PCIDAS6025 }, + { PCI_VDEVICE(CB, 0x005f), BOARD_PCIDAS6030 }, + { PCI_VDEVICE(CB, 0x0060), BOARD_PCIDAS6031 }, + { PCI_VDEVICE(CB, 0x0061), BOARD_PCIDAS6032 }, + { PCI_VDEVICE(CB, 0x0062), BOARD_PCIDAS6033 }, + { PCI_VDEVICE(CB, 0x0063), BOARD_PCIDAS6034 }, + { PCI_VDEVICE(CB, 0x0064), BOARD_PCIDAS6035 }, + { PCI_VDEVICE(CB, 0x0065), BOARD_PCIDAS6040 }, + { PCI_VDEVICE(CB, 0x0066), BOARD_PCIDAS6052 }, + { PCI_VDEVICE(CB, 0x0067), BOARD_PCIDAS6070 }, + { PCI_VDEVICE(CB, 0x0068), BOARD_PCIDAS6071 }, + { PCI_VDEVICE(CB, 0x006f), BOARD_PCIDAS6036 }, + { PCI_VDEVICE(CB, 0x0078), BOARD_PCIDAS6013 }, + { PCI_VDEVICE(CB, 0x0079), BOARD_PCIDAS6014 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cb_pcidas64_pci_table); - /* get acknowledge */ - if (i2c_read_ack(dev) != 0) { - comedi_error(dev, "i2c write failed: no acknowledge"); - i2c_stop(dev); - return; - } - /* write data bytes */ - for (i = 0; i < length; i++) { - i2c_write_byte(dev, data[i]); - if (i2c_read_ack(dev) != 0) { - comedi_error(dev, "i2c write failed: no acknowledge"); - i2c_stop(dev); - return; - } - } - i2c_stop(dev); -} +static struct pci_driver cb_pcidas64_pci_driver = { + .name = "cb_pcidas64", + .id_table = cb_pcidas64_pci_table, + .probe = cb_pcidas64_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(cb_pcidas64_driver, cb_pcidas64_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 49102b3a6c4..901dc5d1bb7 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -1,668 +1,166 @@ /* - comedi/drivers/cb_pcidda.c - This intends to be a driver for the ComputerBoards / MeasurementComputing - PCI-DDA series. - - Copyright (C) 2001 Ivan Martinez <ivanmr@altavista.com> - Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net> - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * comedi/drivers/cb_pcidda.c + * Driver for the ComputerBoards / MeasurementComputing PCI-DDA series. + * + * Copyright (C) 2001 Ivan Martinez <ivanmr@altavista.com> + * Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -*/ /* -Driver: cb_pcidda -Description: MeasurementComputing PCI-DDA series -Author: Ivan Martinez <ivanmr@altavista.com>, Frank Mori Hess <fmhess@users.sourceforge.net> -Status: Supports 08/16, 04/16, 02/16, 08/12, 04/12, and 02/12 -Devices: [Measurement Computing] PCI-DDA08/12 (cb_pcidda), PCI-DDA04/12, - PCI-DDA02/12, PCI-DDA08/16, PCI-DDA04/16, PCI-DDA02/16 - -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. - -Only simple analog output writing is supported. - -So far it has only been tested with: - - PCI-DDA08/12 -Please report success/failure with other different cards to -<comedi@comedi.org>. -*/ + * Driver: cb_pcidda + * Description: MeasurementComputing PCI-DDA series + * Devices: (Measurement Computing) PCI-DDA08/12 [pci-dda08/12] + * (Measurement Computing) PCI-DDA04/12 [pci-dda04/12] + * (Measurement Computing) PCI-DDA02/12 [pci-dda02/12] + * (Measurement Computing) PCI-DDA08/16 [pci-dda08/16] + * (Measurement Computing) PCI-DDA04/16 [pci-dda04/16] + * (Measurement Computing) PCI-DDA02/16 [pci-dda02/16] + * Author: Ivan Martinez <ivanmr@altavista.com> + * Frank Mori Hess <fmhess@users.sourceforge.net> + * Status: works + * + * Configuration options: not applicable, uses PCI auto config + * + * Only simple analog output writing is supported. + */ + +#include <linux/module.h> +#include <linux/pci.h> #include "../comedidev.h" -#include "comedi_pci.h" +#include "comedi_fc.h" #include "8255.h" -#define PCI_VENDOR_ID_CB 0x1307 /* PCI vendor number of ComputerBoards */ #define EEPROM_SIZE 128 /* number of entries in eeprom */ -#define MAX_AO_CHANNELS 8 /* maximum number of ao channels for supported boards */ - -/* PCI-DDA base addresses */ -#define DIGITALIO_BADRINDEX 2 - /* DIGITAL I/O is pci_dev->resource[2] */ -#define DIGITALIO_SIZE 8 - /* DIGITAL I/O uses 8 I/O port addresses */ -#define DAC_BADRINDEX 3 - /* DAC is pci_dev->resource[3] */ +/* maximum number of ao channels for supported boards */ +#define MAX_AO_CHANNELS 8 /* Digital I/O registers */ -#define PORT1A 0 /* PORT 1A DATA */ - -#define PORT1B 1 /* PORT 1B DATA */ - -#define PORT1C 2 /* PORT 1C DATA */ - -#define CONTROL1 3 /* CONTROL REGISTER 1 */ - -#define PORT2A 4 /* PORT 2A DATA */ - -#define PORT2B 5 /* PORT 2B DATA */ - -#define PORT2C 6 /* PORT 2C DATA */ - -#define CONTROL2 7 /* CONTROL REGISTER 2 */ +#define CB_DDA_DIO0_8255_BASE 0x00 +#define CB_DDA_DIO1_8255_BASE 0x04 /* DAC registers */ -#define DACONTROL 0 /* D/A CONTROL REGISTER */ -#define SU 0000001 /* Simultaneous update enabled */ -#define NOSU 0000000 /* Simultaneous update disabled */ -#define ENABLEDAC 0000002 /* Enable specified DAC */ -#define DISABLEDAC 0000000 /* Disable specified DAC */ -#define RANGE2V5 0000000 /* 2.5V */ -#define RANGE5V 0000200 /* 5V */ -#define RANGE10V 0000300 /* 10V */ -#define UNIP 0000400 /* Unipolar outputs */ -#define BIP 0000000 /* Bipolar outputs */ +#define CB_DDA_DA_CTRL_REG 0x00 /* D/A Control Register */ +#define CB_DDA_DA_CTRL_SU (1 << 0) /* Simultaneous update */ +#define CB_DDA_DA_CTRL_EN (1 << 1) /* Enable specified DAC */ +#define CB_DDA_DA_CTRL_DAC(x) ((x) << 2) /* Specify DAC channel */ +#define CB_DDA_DA_CTRL_RANGE2V5 (0 << 6) /* 2.5V range */ +#define CB_DDA_DA_CTRL_RANGE5V (2 << 6) /* 5V range */ +#define CB_DDA_DA_CTRL_RANGE10V (3 << 6) /* 10V range */ +#define CB_DDA_DA_CTRL_UNIP (1 << 8) /* Unipolar range */ #define DACALIBRATION1 4 /* D/A CALIBRATION REGISTER 1 */ /* write bits */ -#define SERIAL_IN_BIT 0x1 /* serial data input for eeprom, caldacs, reference dac */ +/* serial data input for eeprom, caldacs, reference dac */ +#define SERIAL_IN_BIT 0x1 #define CAL_CHANNEL_MASK (0x7 << 1) #define CAL_CHANNEL_BITS(channel) (((channel) << 1) & CAL_CHANNEL_MASK) /* read bits */ #define CAL_COUNTER_MASK 0x1f -#define CAL_COUNTER_OVERFLOW_BIT 0x20 /* calibration counter overflow status bit */ -#define AO_BELOW_REF_BIT 0x40 /* analog output is less than reference dac voltage */ +/* calibration counter overflow status bit */ +#define CAL_COUNTER_OVERFLOW_BIT 0x20 +/* analog output is less than reference dac voltage */ +#define AO_BELOW_REF_BIT 0x40 #define SERIAL_OUT_BIT 0x80 /* serial data out, for reading from eeprom */ #define DACALIBRATION2 6 /* D/A CALIBRATION REGISTER 2 */ #define SELECT_EEPROM_BIT 0x1 /* send serial data in to eeprom */ -#define DESELECT_REF_DAC_BIT 0x2 /* don't send serial data to MAX542 reference dac */ -#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) /* don't send serial data to caldac n */ -#define DUMMY_BIT 0x40 /* manual says to set this bit with no explanation */ +/* don't send serial data to MAX542 reference dac */ +#define DESELECT_REF_DAC_BIT 0x2 +/* don't send serial data to caldac n */ +#define DESELECT_CALDAC_BIT(n) (0x4 << (n)) +/* manual says to set this bit with no explanation */ +#define DUMMY_BIT 0x40 -#define DADATA 8 /* FIRST D/A DATA REGISTER (0) */ +#define CB_DDA_DA_DATA_REG(x) (0x08 + ((x) * 2)) + +/* Offsets for the caldac channels */ +#define CB_DDA_CALDAC_FINE_GAIN 0 +#define CB_DDA_CALDAC_COURSE_GAIN 1 +#define CB_DDA_CALDAC_COURSE_OFFSET 2 +#define CB_DDA_CALDAC_FINE_OFFSET 3 static const struct comedi_lrange cb_pcidda_ranges = { - 6, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - } + 6, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5) + } +}; + +enum cb_pcidda_boardid { + BOARD_DDA02_12, + BOARD_DDA04_12, + BOARD_DDA08_12, + BOARD_DDA02_16, + BOARD_DDA04_16, + BOARD_DDA08_16, }; -/* - * 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. - */ struct cb_pcidda_board { const char *name; - char status; /* Driver status: */ - - /* - * 0 - tested - * 1 - manual read, not tested - * 2 - manual not read - */ - - unsigned short device_id; int ao_chans; int ao_bits; - const struct comedi_lrange *ranges; }; static const struct cb_pcidda_board cb_pcidda_boards[] = { - { - .name = "pci-dda02/12", - .status = 1, - .device_id = 0x20, - .ao_chans = 2, - .ao_bits = 12, - .ranges = &cb_pcidda_ranges, - }, - { - .name = "pci-dda04/12", - .status = 1, - .device_id = 0x21, - .ao_chans = 4, - .ao_bits = 12, - .ranges = &cb_pcidda_ranges, - }, - { - .name = "pci-dda08/12", - .status = 0, - .device_id = 0x22, - .ao_chans = 8, - .ao_bits = 12, - .ranges = &cb_pcidda_ranges, - }, - { - .name = "pci-dda02/16", - .status = 2, - .device_id = 0x23, - .ao_chans = 2, - .ao_bits = 16, - .ranges = &cb_pcidda_ranges, - }, - { - .name = "pci-dda04/16", - .status = 2, - .device_id = 0x24, - .ao_chans = 4, - .ao_bits = 16, - .ranges = &cb_pcidda_ranges, - }, - { - .name = "pci-dda08/16", - .status = 0, - .device_id = 0x25, - .ao_chans = 8, - .ao_bits = 16, - .ranges = &cb_pcidda_ranges, - }, + [BOARD_DDA02_12] = { + .name = "pci-dda02/12", + .ao_chans = 2, + .ao_bits = 12, + }, + [BOARD_DDA04_12] = { + .name = "pci-dda04/12", + .ao_chans = 4, + .ao_bits = 12, + }, + [BOARD_DDA08_12] = { + .name = "pci-dda08/12", + .ao_chans = 8, + .ao_bits = 12, + }, + [BOARD_DDA02_16] = { + .name = "pci-dda02/16", + .ao_chans = 2, + .ao_bits = 16, + }, + [BOARD_DDA04_16] = { + .name = "pci-dda04/16", + .ao_chans = 4, + .ao_bits = 16, + }, + [BOARD_DDA08_16] = { + .name = "pci-dda08/16", + .ao_chans = 8, + .ao_bits = 16, + }, }; -static DEFINE_PCI_DEVICE_TABLE(cb_pcidda_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0020) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0021) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0022) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0023) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0024) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0025) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table); - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct cb_pcidda_board *)dev->board_ptr) - -/* 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 cb_pcidda_private { - int data; - - /* would be useful for a PCI device */ - struct pci_dev *pci_dev; - - unsigned long digitalio; - unsigned long dac; - - /* unsigned long control_status; */ - /* unsigned long adc_fifo; */ - - unsigned int dac_cal1_bits; /* bits last written to da calibration register 1 */ - unsigned int ao_range[MAX_AO_CHANNELS]; /* current range settings for output channels */ + /* bits last written to da calibration register 1 */ + unsigned int dac_cal1_bits; + /* current range settings for output channels */ + unsigned int ao_range[MAX_AO_CHANNELS]; u16 eeprom_data[EEPROM_SIZE]; /* software copy of board's eeprom */ }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct cb_pcidda_private *)dev->private) - -static int cb_pcidda_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int cb_pcidda_detach(struct comedi_device *dev); -/* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */ -static int cb_pcidda_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* static int cb_pcidda_ai_cmd(struct comedi_device *dev, struct *comedi_subdevice *s);*/ -/* static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); */ -/* static int cb_pcidda_ns_to_timer(unsigned int *ns,int *round); */ - -static unsigned int cb_pcidda_serial_in(struct comedi_device *dev); -static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, - unsigned int num_bits); -static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, - unsigned int address); -static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, - unsigned int range); - -/* - * 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 driver_cb_pcidda = { - .driver_name = "cb_pcidda", - .module = THIS_MODULE, - .attach = cb_pcidda_attach, - .detach = cb_pcidda_detach, -}; - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. - */ -static int cb_pcidda_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - struct pci_dev *pcidev = NULL; - int index; - - printk("comedi%d: cb_pcidda: ", dev->minor); - -/* - * Allocate the private structure area. - */ - if (alloc_private(dev, sizeof(struct cb_pcidda_private)) < 0) - return -ENOMEM; - -/* - * Probe the device to determine what device in the series it is. - */ - printk("\n"); - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_CB) { - if (it->options[0] || it->options[1]) { - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - for (index = 0; index < ARRAY_SIZE(cb_pcidda_boards); index++) { - if (cb_pcidda_boards[index].device_id == - pcidev->device) { - goto found; - } - } - } - } - if (!pcidev) { - printk - ("Not a ComputerBoards/MeasurementComputing card on requested position\n"); - return -EIO; - } -found: - devpriv->pci_dev = pcidev; - dev->board_ptr = cb_pcidda_boards + index; - /* "thisboard" macro can be used from here. */ - printk("Found %s at requested position\n", thisboard->name); - - /* - * Enable PCI device and request regions. - */ - if (comedi_pci_enable(pcidev, thisboard->name)) { - printk - ("cb_pcidda: failed to enable PCI device and request regions\n"); - return -EIO; - } - -/* - * Allocate the I/O ports. - */ - devpriv->digitalio = - pci_resource_start(devpriv->pci_dev, DIGITALIO_BADRINDEX); - devpriv->dac = pci_resource_start(devpriv->pci_dev, DAC_BADRINDEX); - -/* - * Warn about the status of the driver. - */ - if (thisboard->status == 2) - printk - ("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. " - "WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. " - "PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n"); - -/* - * Initialize dev->board_name. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the subdevice structures. - */ - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->ao_chans; - s->maxdata = (1 << thisboard->ao_bits) - 1; - s->range_table = thisboard->ranges; - s->insn_write = cb_pcidda_ao_winsn; - - /* s->subdev_flags |= SDF_CMD_READ; */ - /* s->do_cmd = cb_pcidda_ai_cmd; */ - /* s->do_cmdtest = cb_pcidda_ai_cmdtest; */ - - /* two 8255 digital io subdevices */ - s = dev->subdevices + 1; - subdev_8255_init(dev, s, NULL, devpriv->digitalio); - s = dev->subdevices + 2; - subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A); - - printk(" eeprom:"); - for (index = 0; index < EEPROM_SIZE; index++) { - devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index); - printk(" %i:0x%x ", index, devpriv->eeprom_data[index]); - } - printk("\n"); - - /* set calibrations dacs */ - for (index = 0; index < thisboard->ao_chans; index++) - cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int cb_pcidda_detach(struct comedi_device *dev) -{ -/* - * Deallocate the I/O ports. - */ - if (devpriv) { - if (devpriv->pci_dev) { - if (devpriv->dac) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - } - /* cleanup 8255 */ - if (dev->subdevices) { - subdev_8255_cleanup(dev, dev->subdevices + 1); - subdev_8255_cleanup(dev, dev->subdevices + 2); - } - - printk("comedi%d: cb_pcidda: remove\n", dev->minor); - - return 0; -} - -/* - * I will program this later... ;-) - */ -#if 0 -static int cb_pcidda_ai_cmd(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - printk("cb_pcidda_ai_cmd\n"); - printk("subdev: %d\n", cmd->subdev); - printk("flags: %d\n", cmd->flags); - printk("start_src: %d\n", cmd->start_src); - printk("start_arg: %d\n", cmd->start_arg); - printk("scan_begin_src: %d\n", cmd->scan_begin_src); - printk("convert_src: %d\n", cmd->convert_src); - printk("convert_arg: %d\n", cmd->convert_arg); - printk("scan_end_src: %d\n", cmd->scan_end_src); - printk("scan_end_arg: %d\n", cmd->scan_end_arg); - printk("stop_src: %d\n", cmd->stop_src); - printk("stop_arg: %d\n", cmd->stop_arg); - printk("chanlist_len: %d\n", cmd->chanlist_len); -} -#endif - -#if 0 -static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - int err = 0; - int tmp; - - /* 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. */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) - return 1; - - /* step 2: make sure trigger sources are unique and mutually compatible */ - - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER - && cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT) - err++; - - if (err) - return 2; - - /* step 3: make sure arguments are trivially compatible */ - - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } -#define MAX_SPEED 10000 /* in nanoseconds */ -#define MIN_SPEED 1000000000 /* in nanoseconds */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < MAX_SPEED) { - cmd->scan_begin_arg = MAX_SPEED; - err++; - } - if (cmd->scan_begin_arg > MIN_SPEED) { - cmd->scan_begin_arg = MIN_SPEED; - err++; - } - } else { - /* external trigger */ - /* should be level/edge, hi/lo specification here */ - /* should specify multiple external triggers */ - if (cmd->scan_begin_arg > 9) { - cmd->scan_begin_arg = 9; - err++; - } - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < MAX_SPEED) { - cmd->convert_arg = MAX_SPEED; - err++; - } - if (cmd->convert_arg > MIN_SPEED) { - cmd->convert_arg = MIN_SPEED; - err++; - } - } else { - /* external trigger */ - /* see above */ - if (cmd->convert_arg > 9) { - cmd->convert_arg = 9; - err++; - } - } - - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg > 0x00ffffff) { - cmd->stop_arg = 0x00ffffff; - err++; - } - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - cb_pcidda_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - cb_pcidda_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } - - if (err) - return 4; - - return 0; -} -#endif - -/* 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. */ -#if 0 -static int cb_pcidda_ns_to_timer(unsigned int *ns, int round) -{ - /* trivial timer */ - return *ns; -} -#endif - -static int cb_pcidda_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int command; - unsigned int channel, range; - - channel = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); - - /* adjust calibration dacs if range has changed */ - if (range != devpriv->ao_range[channel]) - cb_pcidda_calibrate(dev, channel, range); - - /* output channel configuration */ - command = NOSU | ENABLEDAC; - - /* output channel range */ - switch (range) { - case 0: - command |= BIP | RANGE10V; - break; - case 1: - command |= BIP | RANGE5V; - break; - case 2: - command |= BIP | RANGE2V5; - break; - case 3: - command |= UNIP | RANGE10V; - break; - case 4: - command |= UNIP | RANGE5V; - break; - case 5: - command |= UNIP | RANGE2V5; - break; - } - - /* output channel specification */ - command |= channel << 2; - outw(command, devpriv->dac + DACONTROL); - - /* write data */ - outw(data[0], devpriv->dac + DADATA + channel * 2); - - /* return the number of samples read/written */ - return 1; -} - /* lowlevel read from eeprom */ static unsigned int cb_pcidda_serial_in(struct comedi_device *dev) { @@ -672,7 +170,7 @@ static unsigned int cb_pcidda_serial_in(struct comedi_device *dev) for (i = 1; i <= value_width; i++) { /* read bits most significant bit first */ - if (inw_p(devpriv->dac + DACALIBRATION1) & SERIAL_OUT_BIT) + if (inw_p(dev->iobase + DACALIBRATION1) & SERIAL_OUT_BIT) value |= 1 << (value_width - i); } @@ -683,6 +181,7 @@ static unsigned int cb_pcidda_serial_in(struct comedi_device *dev) static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, unsigned int num_bits) { + struct cb_pcidda_private *devpriv = dev->private; int i; for (i = 1; i <= num_bits; i++) { @@ -691,7 +190,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, devpriv->dac + DACALIBRATION1); + outw_p(devpriv->dac_cal1_bits, dev->iobase + DACALIBRATION1); } } @@ -702,8 +201,10 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, unsigned int i; unsigned int cal2_bits; unsigned int value; - const int max_num_caldacs = 4; /* one caldac for every two dac channels */ - const int read_instruction = 0x6; /* bits to send to tell eeprom we want to read */ + /* one caldac for every two dac channels */ + const int max_num_caldacs = 4; + /* bits to send to tell eeprom we want to read */ + const int read_instruction = 0x6; const int instruction_length = 3; const int address_length = 8; @@ -712,7 +213,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, devpriv->dac + DACALIBRATION2); + outw_p(cal2_bits, dev->iobase + DACALIBRATION2); /* tell eeprom we want to read */ cb_pcidda_serial_out(dev, read_instruction, instruction_length); @@ -723,7 +224,7 @@ static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, /* deactivate eeprom */ cal2_bits &= ~SELECT_EEPROM_BIT; - outw_p(cal2_bits, devpriv->dac + DACALIBRATION2); + outw_p(cal2_bits, dev->iobase + DACALIBRATION2); return value; } @@ -735,9 +236,11 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev, { unsigned int cal2_bits; unsigned int i; - const int num_channel_bits = 3; /* caldacs use 3 bit channel specification */ + /* caldacs use 3 bit channel specification */ + const int num_channel_bits = 3; const int num_caldac_bits = 8; /* 8 bit calibration dacs */ - const int max_num_caldacs = 4; /* one caldac for every two dac channels */ + /* one caldac for every two dac channels */ + const int max_num_caldacs = 4; /* write 3 bit channel */ cb_pcidda_serial_out(dev, channel, num_channel_bits); @@ -753,143 +256,173 @@ 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, devpriv->dac + DACALIBRATION2); + outw_p(cal2_bits, dev->iobase + DACALIBRATION2); /* deactivate caldac */ cal2_bits |= DESELECT_CALDAC_BIT(caldac); - outw_p(cal2_bits, devpriv->dac + DACALIBRATION2); + outw_p(cal2_bits, dev->iobase + DACALIBRATION2); } -/* returns caldac that calibrates given analog out channel */ -static unsigned int caldac_number(unsigned int channel) +/* set caldacs to eeprom values for given channel and range */ +static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, + unsigned int range) { - return channel / 2; -} + struct cb_pcidda_private *devpriv = dev->private; + unsigned int caldac = channel / 2; /* two caldacs per channel */ + unsigned int chan = 4 * (channel % 2); /* caldac channel base */ + unsigned int index = 2 * range + 12 * channel; + unsigned int offset; + unsigned int gain; + + /* save range so we can tell when we need to readjust calibration */ + devpriv->ao_range[channel] = range; -/* returns caldac channel that provides fine gain for given ao channel */ -static unsigned int fine_gain_channel(unsigned int ao_channel) -{ - return 4 * (ao_channel % 2); + /* get values from eeprom data */ + offset = devpriv->eeprom_data[0x7 + index]; + gain = devpriv->eeprom_data[0x8 + index]; + + /* set caldacs */ + cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_COURSE_OFFSET, + (offset >> 8) & 0xff); + cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_FINE_OFFSET, + offset & 0xff); + cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_COURSE_GAIN, + (gain >> 8) & 0xff); + cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_FINE_GAIN, + gain & 0xff); } -/* returns caldac channel that provides coarse gain for given ao channel */ -static unsigned int coarse_gain_channel(unsigned int ao_channel) +static int cb_pcidda_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - return 1 + 4 * (ao_channel % 2); -} + struct cb_pcidda_private *devpriv = dev->private; + unsigned int channel = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int ctrl; -/* returns caldac channel that provides coarse offset for given ao channel */ -static unsigned int coarse_offset_channel(unsigned int ao_channel) -{ - return 2 + 4 * (ao_channel % 2); -} + if (range != devpriv->ao_range[channel]) + cb_pcidda_calibrate(dev, channel, range); -/* returns caldac channel that provides fine offset for given ao channel */ -static unsigned int fine_offset_channel(unsigned int ao_channel) -{ - return 3 + 4 * (ao_channel % 2); -} + ctrl = CB_DDA_DA_CTRL_EN | CB_DDA_DA_CTRL_DAC(channel); -/* returns eeprom address that provides offset for given ao channel and range */ -static unsigned int offset_eeprom_address(unsigned int ao_channel, - unsigned int range) -{ - return 0x7 + 2 * range + 12 * ao_channel; -} + switch (range) { + case 0: + case 3: + ctrl |= CB_DDA_DA_CTRL_RANGE10V; + break; + case 1: + case 4: + ctrl |= CB_DDA_DA_CTRL_RANGE5V; + break; + case 2: + case 5: + ctrl |= CB_DDA_DA_CTRL_RANGE2V5; + break; + } -/* returns eeprom address that provides gain calibration for given ao channel and range */ -static unsigned int gain_eeprom_address(unsigned int ao_channel, - unsigned int range) -{ - return 0x8 + 2 * range + 12 * ao_channel; -} + if (range > 2) + ctrl |= CB_DDA_DA_CTRL_UNIP; -/* returns upper byte of eeprom entry, which gives the coarse adjustment values */ -static unsigned int eeprom_coarse_byte(unsigned int word) -{ - return (word >> 8) & 0xff; -} + outw(ctrl, dev->iobase + CB_DDA_DA_CTRL_REG); -/* returns lower byte of eeprom entry, which gives the fine adjustment values */ -static unsigned int eeprom_fine_byte(unsigned int word) -{ - return word & 0xff; + outw(data[0], dev->iobase + CB_DDA_DA_DATA_REG(channel)); + + return insn->n; } -/* set caldacs to eeprom values for given channel and range */ -static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, - unsigned int range) +static int cb_pcidda_auto_attach(struct comedi_device *dev, + unsigned long context) { - unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain; + struct pci_dev *pcidev = comedi_to_pci_dev(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; - /* remember range so we can tell when we need to readjust calibration */ - devpriv->ao_range[channel] = range; + if (context < ARRAY_SIZE(cb_pcidda_boards)) + thisboard = &cb_pcidda_boards[context]; + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; - /* get values from eeprom data */ - coarse_offset = - eeprom_coarse_byte(devpriv->eeprom_data - [offset_eeprom_address(channel, range)]); - fine_offset = - eeprom_fine_byte(devpriv->eeprom_data - [offset_eeprom_address(channel, range)]); - coarse_gain = - eeprom_coarse_byte(devpriv->eeprom_data - [gain_eeprom_address(channel, range)]); - fine_gain = - eeprom_fine_byte(devpriv->eeprom_data - [gain_eeprom_address(channel, range)]); - - /* set caldacs */ - cb_pcidda_write_caldac(dev, caldac_number(channel), - coarse_offset_channel(channel), coarse_offset); - cb_pcidda_write_caldac(dev, caldac_number(channel), - fine_offset_channel(channel), fine_offset); - cb_pcidda_write_caldac(dev, caldac_number(channel), - coarse_gain_channel(channel), coarse_gain); - cb_pcidda_write_caldac(dev, caldac_number(channel), - fine_gain_channel(channel), fine_gain); -} + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_cb_pcidda_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_cb_pcidda.driver_name); -} + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 3); + iobase_8255 = pci_resource_start(pcidev, 2); -static void __devexit driver_cb_pcidda_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; -static struct pci_driver driver_cb_pcidda_pci_driver = { - .id_table = cb_pcidda_pci_table, - .probe = &driver_cb_pcidda_pci_probe, - .remove = __devexit_p(&driver_cb_pcidda_pci_remove) -}; + s = &dev->subdevices[0]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = thisboard->ao_chans; + s->maxdata = (1 << thisboard->ao_bits) - 1; + s->range_table = &cb_pcidda_ranges; + s->insn_write = cb_pcidda_ao_insn_write; + + /* 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)); + if (ret) + return ret; + } -static int __init driver_cb_pcidda_init_module(void) -{ - int retval; + /* Read the caldac eeprom data */ + for (i = 0; i < EEPROM_SIZE; i++) + devpriv->eeprom_data[i] = cb_pcidda_read_eeprom(dev, i); - retval = comedi_driver_register(&driver_cb_pcidda); - if (retval < 0) - return retval; + /* set calibrations dacs */ + for (i = 0; i < thisboard->ao_chans; i++) + cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]); - driver_cb_pcidda_pci_driver.name = (char *)driver_cb_pcidda.driver_name; - return pci_register_driver(&driver_cb_pcidda_pci_driver); + return 0; } -static void __exit driver_cb_pcidda_cleanup_module(void) +static struct comedi_driver cb_pcidda_driver = { + .driver_name = "cb_pcidda", + .module = THIS_MODULE, + .auto_attach = cb_pcidda_auto_attach, + .detach = comedi_pci_disable, +}; + +static int cb_pcidda_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - pci_unregister_driver(&driver_cb_pcidda_pci_driver); - comedi_driver_unregister(&driver_cb_pcidda); + return comedi_pci_auto_config(dev, &cb_pcidda_driver, + id->driver_data); } -module_init(driver_cb_pcidda_init_module); -module_exit(driver_cb_pcidda_cleanup_module); +static const struct pci_device_id cb_pcidda_pci_table[] = { + { PCI_VDEVICE(CB, 0x0020), BOARD_DDA02_12 }, + { PCI_VDEVICE(CB, 0x0021), BOARD_DDA04_12 }, + { PCI_VDEVICE(CB, 0x0022), BOARD_DDA08_12 }, + { PCI_VDEVICE(CB, 0x0023), BOARD_DDA02_16 }, + { PCI_VDEVICE(CB, 0x0024), BOARD_DDA04_16 }, + { PCI_VDEVICE(CB, 0x0025), BOARD_DDA08_16 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table); + +static struct pci_driver cb_pcidda_pci_driver = { + .name = "cb_pcidda", + .id_table = cb_pcidda_pci_table, + .probe = cb_pcidda_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c deleted file mode 100644 index 79477a595ef..00000000000 --- a/drivers/staging/comedi/drivers/cb_pcidio.c +++ /dev/null @@ -1,340 +0,0 @@ -/* - comedi/drivers/cb_pcidio.c - A Comedi driver for PCI-DIO24H & PCI-DIO48H of ComputerBoards (currently MeasurementComputing) - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: cb_pcidio -Description: ComputerBoards' DIO boards with PCI interface -Devices: [Measurement Computing] PCI-DIO24 (cb_pcidio), PCI-DIO24H, PCI-DIO48H -Author: Yoshiya Matsuzaka -Updated: Mon, 29 Oct 2007 15:40:47 +0000 -Status: experimental - -This driver has been modified from skel.c of comedi-0.7.70. - -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. - -Passing a zero for an option is the same as leaving it unspecified. -*/ - -/*------------------------------ HEADER FILES ---------------------------------*/ -#include "../comedidev.h" -#include "comedi_pci.h" -#include "8255.h" - -/*-------------------------- MACROS and DATATYPES -----------------------------*/ -#define PCI_VENDOR_ID_CB 0x1307 - -/* - * 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. - */ -struct pcidio_board { - const char *name; /* name of the board */ - int dev_id; - int n_8255; /* number of 8255 chips on board */ - - /* indices of base address regions */ - int pcicontroler_badrindex; - int dioregs_badrindex; -}; - -static const struct pcidio_board pcidio_boards[] = { - { - .name = "pci-dio24", - .dev_id = 0x0028, - .n_8255 = 1, - .pcicontroler_badrindex = 1, - .dioregs_badrindex = 2, - }, - { - .name = "pci-dio24h", - .dev_id = 0x0014, - .n_8255 = 1, - .pcicontroler_badrindex = 1, - .dioregs_badrindex = 2, - }, - { - .name = "pci-dio48h", - .dev_id = 0x000b, - .n_8255 = 2, - .pcicontroler_badrindex = 0, - .dioregs_badrindex = 1, - }, -}; - -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded - * upstream. */ -static DEFINE_PCI_DEVICE_TABLE(pcidio_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, pcidio_pci_table); - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct pcidio_board *)dev->board_ptr) - -/* 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 pcidio_private { - int data; /* currently unused */ - - /* would be useful for a PCI device */ - struct pci_dev *pci_dev; - - /* used for DO readback, currently unused */ - unsigned int do_readback[4]; /* up to 4 unsigned int suffice to hold 96 bits for PCI-DIO96 */ - - unsigned long dio_reg_base; /* address of port A of the first 8255 chip on board */ -}; - -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct pcidio_private *)dev->private) - -/* - * 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 int pcidio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcidio_detach(struct comedi_device *dev); -static struct comedi_driver driver_cb_pcidio = { - .driver_name = "cb_pcidio", - .module = THIS_MODULE, - .attach = pcidio_attach, - .detach = pcidio_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 pcidio_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. - */ - -/* The following fields should NOT be initialized if you are dealing - * with PCI devices - * - * .board_name = pcidio_boards, - * .offset = sizeof(struct pcidio_board), - * .num_names = sizeof(pcidio_boards) / sizeof(structpcidio_board), - */ - -}; - -/*------------------------------- FUNCTIONS -----------------------------------*/ - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int index; - int i; - - printk("comedi%d: cb_pcidio: \n", dev->minor); - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct pcidio_private)) < 0) - return -ENOMEM; -/* - * 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. - */ -/* - * Probe the device to determine what device in the series it is. - */ - - for_each_pci_dev(pcidev) { - /* is it not a computer boards card? */ - if (pcidev->vendor != PCI_VENDOR_ID_CB) - continue; - /* loop through cards supported by this driver */ - for (index = 0; index < ARRAY_SIZE(pcidio_boards); index++) { - if (pcidio_boards[index].dev_id != pcidev->device) - continue; - - /* was a particular bus/slot requested? */ - if (it->options[0] || it->options[1]) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - dev->board_ptr = pcidio_boards + index; - goto found; - } - } - - printk("No supported ComputerBoards/MeasurementComputing card found on " - "requested position\n"); - return -EIO; - -found: - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - - devpriv->pci_dev = pcidev; - printk("Found %s on bus %i, slot %i\n", thisboard->name, - devpriv->pci_dev->bus->number, - PCI_SLOT(devpriv->pci_dev->devfn)); - if (comedi_pci_enable(pcidev, thisboard->name)) { - printk - ("cb_pcidio: failed to enable PCI device and request regions\n"); - return -EIO; - } - devpriv->dio_reg_base - = - pci_resource_start(devpriv->pci_dev, - pcidio_boards[index].dioregs_badrindex); - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, thisboard->n_8255) < 0) - return -ENOMEM; - - for (i = 0; i < thisboard->n_8255; i++) { - subdev_8255_init(dev, dev->subdevices + i, - NULL, devpriv->dio_reg_base + i * 4); - printk(" subdev %d: base = 0x%lx\n", i, - devpriv->dio_reg_base + i * 4); - } - - printk("attached\n"); - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pcidio_detach(struct comedi_device *dev) -{ - printk("comedi%d: cb_pcidio: remove\n", dev->minor); - if (devpriv) { - if (devpriv->pci_dev) { - if (devpriv->dio_reg_base) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - } - if (dev->subdevices) { - int i; - for (i = 0; i < thisboard->n_8255; i++) - subdev_8255_cleanup(dev, dev->subdevices + i); - } - return 0; -} - -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_cb_pcidio_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_cb_pcidio.driver_name); -} - -static void __devexit driver_cb_pcidio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_cb_pcidio_pci_driver = { - .id_table = pcidio_pci_table, - .probe = &driver_cb_pcidio_pci_probe, - .remove = __devexit_p(&driver_cb_pcidio_pci_remove) -}; - -static int __init driver_cb_pcidio_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_cb_pcidio); - if (retval < 0) - return retval; - - driver_cb_pcidio_pci_driver.name = (char *)driver_cb_pcidio.driver_name; - return pci_register_driver(&driver_cb_pcidio_pci_driver); -} - -static void __exit driver_cb_pcidio_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcidio_pci_driver); - comedi_driver_unregister(&driver_cb_pcidio); -} - -module_init(driver_cb_pcidio_init_module); -module_exit(driver_cb_pcidio_cleanup_module); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index b1b832b65bc..50e522e6e69 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: cb_pcimdas @@ -36,32 +31,24 @@ Configuration Options: Developed from cb_pcidas and skel by Richard Bytheway (mocelet@sucs.org). Only supports DIO, AO and simple AI in it's present form. -No interrupts, multi channel or FIFO AI, although the card looks like it could support this. +No interrupts, multi channel or FIFO AI, +although the card looks like it could support this. See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. */ -#include "../comedidev.h" - -#include <linux/delay.h> +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> -#include "comedi_pci.h" +#include "../comedidev.h" + #include "plx9052.h" #include "8255.h" -/* #define CBPCIMDAS_DEBUG */ -#undef CBPCIMDAS_DEBUG - -#define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307 - /* Registers for the PCIM-DAS1602/16 */ /* sizes of io regions (bytes) */ -#define BADR0_SIZE 2 /* ?? */ -#define BADR1_SIZE 4 -#define BADR2_SIZE 6 #define BADR3_SIZE 16 -#define BADR4_SIZE 4 /* DAC Offsets */ #define ADC_TRIG 0 @@ -85,314 +72,53 @@ See http://www.mccdaq.com/PDFs/Manuals/pcim-das1602-16.pdf for more details. #define RESID_COUNT_H 13 #define RESID_COUNT_L 14 -/* Board description */ -struct cb_pcimdas_board { - const char *name; - unsigned short device_id; - int ai_se_chans; /* Inputs in single-ended mode */ - int ai_diff_chans; /* Inputs in differential mode */ - int ai_bits; /* analog input resolution */ - int ai_speed; /* fastest conversion period in ns */ - int ao_nchan; /* number of analog out channels */ - int ao_bits; /* analogue output resolution */ - int has_ao_fifo; /* analog output has fifo */ - int ao_scan_speed; /* analog output speed for 1602 series (for a scan, not conversion) */ - int fifo_size; /* number of samples fifo can hold */ - int dio_bits; /* number of dio bits */ - int has_dio; /* has DIO */ - const struct comedi_lrange *ranges; -}; - -static const struct cb_pcimdas_board cb_pcimdas_boards[] = { - { - .name = "PCIM-DAS1602/16", - .device_id = 0x56, - .ai_se_chans = 16, - .ai_diff_chans = 8, - .ai_bits = 16, - .ai_speed = 10000, /* ?? */ - .ao_nchan = 2, - .ao_bits = 12, - .has_ao_fifo = 0, /* ?? */ - .ao_scan_speed = 10000, - /* ?? */ - .fifo_size = 1024, - .dio_bits = 24, - .has_dio = 1, -/* .ranges = &cb_pcimdas_ranges, */ - }, -}; - -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -static DEFINE_PCI_DEVICE_TABLE(cb_pcimdas_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, 0x0056) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table); - -#define N_BOARDS 1 /* Max number of boards supported */ - /* - * Useful for shorthand access to the particular board structure + * 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. */ -#define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr) - -/* 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 cb_pcimdas_private { - int data; - - /* would be useful for a PCI device */ - struct pci_dev *pci_dev; - /* base addresses */ - unsigned long BADR0; - unsigned long BADR1; - unsigned long BADR2; unsigned long BADR3; - unsigned long BADR4; /* Used for AO readback */ unsigned int ao_readback[2]; - - /* Used for DIO */ - unsigned short int port_a; /* copy of BADR4+0 */ - unsigned short int port_b; /* copy of BADR4+1 */ - unsigned short int port_c; /* copy of BADR4+2 */ - unsigned short int dio_mode; /* copy of BADR4+3 */ - -}; - -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct cb_pcimdas_private *)dev->private) - -/* - * 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 int cb_pcimdas_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int cb_pcimdas_detach(struct comedi_device *dev); -static struct comedi_driver driver_cb_pcimdas = { - .driver_name = "cb_pcimdas", - .module = THIS_MODULE, - .attach = cb_pcimdas_attach, - .detach = cb_pcimdas_detach, }; -static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -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_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int cb_pcimdas_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int cb_pcimdas_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - struct comedi_subdevice *s; - struct pci_dev *pcidev = NULL; - int index; - /* int i; */ - - printk("comedi%d: cb_pcimdas: ", dev->minor); - -/* - * Allocate the private structure area. - */ - if (alloc_private(dev, sizeof(struct cb_pcimdas_private)) < 0) - return -ENOMEM; - -/* - * Probe the device to determine what device in the series it is. - */ - printk("\n"); - - for_each_pci_dev(pcidev) { - /* is it not a computer boards card? */ - if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) - continue; - /* loop through cards supported by this driver */ - for (index = 0; index < N_BOARDS; index++) { - if (cb_pcimdas_boards[index].device_id != - pcidev->device) - continue; - /* was a particular bus/slot requested? */ - if (it->options[0] || it->options[1]) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - devpriv->pci_dev = pcidev; - dev->board_ptr = cb_pcimdas_boards + index; - goto found; - } - } - - printk("No supported ComputerBoards/MeasurementComputing card found on " - "requested position\n"); - return -EIO; - -found: - - printk("Found %s on bus %i, slot %i\n", cb_pcimdas_boards[index].name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn)); - - /* Warn about non-tested features */ - switch (thisboard->device_id) { - case 0x56: - break; - default: - printk("THIS CARD IS UNSUPPORTED.\n" - "PLEASE REPORT USAGE TO <mocelet@sucs.org>\n"); - } - - if (comedi_pci_enable(pcidev, "cb_pcimdas")) { - printk(" Failed to enable PCI device and request regions\n"); - return -EIO; - } - - devpriv->BADR0 = pci_resource_start(devpriv->pci_dev, 0); - devpriv->BADR1 = pci_resource_start(devpriv->pci_dev, 1); - devpriv->BADR2 = pci_resource_start(devpriv->pci_dev, 2); - devpriv->BADR3 = pci_resource_start(devpriv->pci_dev, 3); - devpriv->BADR4 = pci_resource_start(devpriv->pci_dev, 4); - -#ifdef CBPCIMDAS_DEBUG - printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0); - printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1); - printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2); - printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3); - printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4); -#endif - -/* Dont support IRQ yet */ -/* get irq */ -/* if(request_irq(devpriv->pci_dev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */ -/* { */ -/* printk(" unable to allocate irq %u\n", devpriv->pci_dev->irq); */ -/* return -EINVAL; */ -/* } */ -/* dev->irq = devpriv->pci_dev->irq; */ - - /* Initialize dev->board_name */ - dev->board_name = thisboard->name; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* dev->read_subdev=s; */ - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = thisboard->ai_se_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = &range_unknown; - s->len_chanlist = 1; /* This is the maximum chanlist length that */ - /* the board can handle */ - s->insn_read = cb_pcimdas_ai_rinsn; + struct cb_pcimdas_private *devpriv = dev->private; + unsigned int status; - s = dev->subdevices + 1; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->ao_nchan; - s->maxdata = 1 << thisboard->ao_bits; - s->range_table = &range_unknown; /* ranges are hardware settable, but not software readable. */ - s->insn_write = &cb_pcimdas_ao_winsn; - s->insn_read = &cb_pcimdas_ao_rinsn; - - s = dev->subdevices + 2; - /* digital i/o subdevice */ - if (thisboard->has_dio) - subdev_8255_init(dev, s, NULL, devpriv->BADR4); - else - s->type = COMEDI_SUBD_UNUSED; - - printk("attached\n"); - - return 1; + status = inb(devpriv->BADR3 + 2); + if ((status & 0x80) == 0) + return 0; + return -EBUSY; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int cb_pcimdas_detach(struct comedi_device *dev) -{ -#ifdef CBPCIMDAS_DEBUG - if (devpriv) { - printk("devpriv->BADR0 = 0x%lx\n", devpriv->BADR0); - printk("devpriv->BADR1 = 0x%lx\n", devpriv->BADR1); - printk("devpriv->BADR2 = 0x%lx\n", devpriv->BADR2); - printk("devpriv->BADR3 = 0x%lx\n", devpriv->BADR3); - printk("devpriv->BADR4 = 0x%lx\n", devpriv->BADR4); - } -#endif - printk("comedi%d: cb_pcimdas: remove\n", dev->minor); - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv) { - if (devpriv->pci_dev) { - if (devpriv->BADR0) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - } - - return 0; -} - -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + struct cb_pcimdas_private *devpriv = dev->private; + int n; unsigned int d; - unsigned int busy; int chan = CR_CHAN(insn->chanspec); unsigned short chanlims; int maxchans; + int ret; /* only support sw initiated reads from a single channel */ /* check channel number */ if ((inb(devpriv->BADR3 + 2) & 0x20) == 0) /* differential mode */ - maxchans = thisboard->ai_diff_chans; + maxchans = s->n_chan / 2; else - maxchans = thisboard->ai_se_chans; + maxchans = s->n_chan; if (chan > (maxchans - 1)) return -ETIMEDOUT; /* *** Wrong error code. Fixme. */ @@ -403,38 +129,32 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, d = d & 0xfd; outb(d, devpriv->BADR3 + 5); } - outb(0x01, devpriv->BADR3 + 6); /* set bursting off, conversions on */ - outb(0x00, devpriv->BADR3 + 7); /* set range to 10V. UP/BP is controlled by a switch on the board */ - /* write channel limits to multiplexer, set Low (bits 0-3) and High (bits 4-7) channels to chan. */ + /* set bursting off, conversions on */ + outb(0x01, devpriv->BADR3 + 6); + + /* set range to 10V. UP/BP is controlled by a switch on the board */ + outb(0x00, devpriv->BADR3 + 7); + + /* + * write channel limits to multiplexer, set Low (bits 0-3) and + * High (bits 4-7) channels to chan. + */ chanlims = chan | (chan << 4); outb(chanlims, devpriv->BADR3 + 0); /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ - outw(0, devpriv->BADR2 + 0); - -#define TIMEOUT 1000 /* typically takes 5 loops on a lightly loaded Pentium 100MHz, */ - /* this is likely to be 100 loops on a 2GHz machine, so set 1000 as the limit. */ + outw(0, dev->iobase + 0); /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - busy = inb(devpriv->BADR3 + 2) & 0x80; - if (!busy) - break; - } - if (i == TIMEOUT) { - printk("timeout\n"); - return -ETIMEDOUT; - } - /* read data */ - d = inw(devpriv->BADR2 + 0); - - /* mangle the data as necessary */ - /* d ^= 1<<(thisboard->ai_bits-1); // 16 bit data from ADC, so no mangle needed. */ + ret = comedi_timeout(dev, s, insn, cb_pcimdas_ai_eoc, 0); + if (ret) + return ret; - data[n] = d; + /* read data */ + data[n] = inw(dev->iobase + 0); } /* return the number of samples read/written */ @@ -445,6 +165,7 @@ static int cb_pcimdas_ao_winsn(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); @@ -453,10 +174,10 @@ static int cb_pcimdas_ao_winsn(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { switch (chan) { case 0: - outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC0_OFFSET); + outw(data[i] & 0x0FFF, dev->iobase + DAC0_OFFSET); break; case 1: - outw(data[i] & 0x0FFF, devpriv->BADR2 + DAC1_OFFSET); + outw(data[i] & 0x0FFF, dev->iobase + DAC1_OFFSET); break; default: return -1; @@ -474,6 +195,7 @@ 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); @@ -483,49 +205,97 @@ static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, return i; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __devinit driver_cb_pcimdas_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static int cb_pcimdas_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - return comedi_pci_auto_config(dev, driver_cb_pcimdas.driver_name); + 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)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 2); + devpriv->BADR3 = pci_resource_start(pcidev, 3); + iobase_8255 = pci_resource_start(pcidev, 4); + + 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; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = 0xffff; + s->range_table = &range_unknown; + s->len_chanlist = 1; /* This is the maximum chanlist length that */ + /* the board can handle */ + s->insn_read = cb_pcimdas_ai_rinsn; + + s = &dev->subdevices[1]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + 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 = &dev->subdevices[2]; + /* digital i/o subdevice */ + ret = subdev_8255_init(dev, s, NULL, iobase_8255); + if (ret) + return ret; + + return 0; } -static void __devexit driver_cb_pcimdas_pci_remove(struct pci_dev *dev) +static void cb_pcimdas_detach(struct comedi_device *dev) { - comedi_pci_auto_unconfig(dev); + if (dev->irq) + free_irq(dev->irq, dev); + comedi_pci_disable(dev); } -static struct pci_driver driver_cb_pcimdas_pci_driver = { - .id_table = cb_pcimdas_pci_table, - .probe = &driver_cb_pcimdas_pci_probe, - .remove = __devexit_p(&driver_cb_pcimdas_pci_remove) +static struct comedi_driver cb_pcimdas_driver = { + .driver_name = "cb_pcimdas", + .module = THIS_MODULE, + .auto_attach = cb_pcimdas_auto_attach, + .detach = cb_pcimdas_detach, }; -static int __init driver_cb_pcimdas_init_module(void) +static int cb_pcimdas_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_cb_pcimdas); - if (retval < 0) - return retval; - - driver_cb_pcimdas_pci_driver.name = - (char *)driver_cb_pcimdas.driver_name; - return pci_register_driver(&driver_cb_pcimdas_pci_driver); + return comedi_pci_auto_config(dev, &cb_pcimdas_driver, + id->driver_data); } -static void __exit driver_cb_pcimdas_cleanup_module(void) -{ - pci_unregister_driver(&driver_cb_pcimdas_pci_driver); - comedi_driver_unregister(&driver_cb_pcimdas); -} +static const struct pci_device_id cb_pcimdas_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0056) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cb_pcimdas_pci_table); -module_init(driver_cb_pcimdas_init_module); -module_exit(driver_cb_pcimdas_cleanup_module); +static struct pci_driver cb_pcimdas_pci_driver = { + .name = "cb_pcimdas", + .id_table = cb_pcimdas_pci_table, + .probe = cb_pcimdas_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(cb_pcimdas_driver, cb_pcimdas_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index 8c981a89ab6..4a2b200de01 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -15,11 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: cb_pcimdda @@ -57,12 +52,7 @@ output modes on the board: then issue one comedi_data_read() on any channel on the AO subdevice to initiate the simultaneous XFER. -Configuration Options: - [0] PCI bus (optional) - [1] PCI slot (optional) - [2] analog output range jumper setting - 0 == +/- 5 V - 1 == +/- 10 V +Configuration Options: not applicable, uses PCI auto config */ /* @@ -84,426 +74,152 @@ Configuration Options: -Calin Culianu <calin@ajvar.org> */ -#include "../comedidev.h" +#include <linux/module.h> +#include <linux/pci.h> -#include "comedi_pci.h" +#include "../comedidev.h" #include "8255.h" /* device ids of the cards we support -- currently only 1 card supported */ -#define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307 #define PCI_ID_PCIM_DDA06_16 0x0053 /* - * This is straight from skel.c -- I did this in case this source file - * will someday support more than 1 board... + * Register map, 8-bit access only */ -struct board_struct { - const char *name; - unsigned short device_id; - int ao_chans; - int ao_bits; - int dio_chans; - int dio_method; - int dio_offset; /* how many bytes into the BADR are the DIO ports */ - int regs_badrindex; /* IO Region for the control, analog output, - and DIO registers */ - int reg_sz; /* number of bytes of registers in io region */ -}; - -enum DIO_METHODS { - DIO_NONE = 0, - DIO_8255, - DIO_INTERNAL /* unimplemented */ -}; +#define PCIMDDA_DA_CHAN(x) (0x00 + (x) * 2) +#define PCIMDDA_8255_BASE_REG 0x0c -static const struct board_struct boards[] = { - { - .name = "cb_pcimdda06-16", - .device_id = PCI_ID_PCIM_DDA06_16, - .ao_chans = 6, - .ao_bits = 16, - .dio_chans = 24, - .dio_method = DIO_8255, - .dio_offset = 12, - .regs_badrindex = 3, - .reg_sz = 16, - } -}; +#define MAX_AO_READBACK_CHANNELS 6 -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct board_struct *)dev->board_ptr) - -#define REG_SZ (thisboard->reg_sz) -#define REGS_BADRINDEX (thisboard->regs_badrindex) - -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded - * upstream. */ -static DEFINE_PCI_DEVICE_TABLE(pci_table) = { - { - PCI_VENDOR_ID_COMPUTERBOARDS, PCI_ID_PCIM_DDA06_16, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, pci_table); - -/* 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 board_private_struct { - unsigned long registers; /* set by probe */ - unsigned long dio_registers; - char attached_to_8255; /* boolean */ - char attached_successfully; /* boolean */ - /* would be useful for a PCI device */ - struct pci_dev *pci_dev; - -#define MAX_AO_READBACK_CHANNELS 6 - /* Used for AO readback */ +struct cb_pcimdda_private { unsigned int ao_readback[MAX_AO_READBACK_CHANNELS]; - -}; - -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct board_private_struct *)dev->private) - -/* - * 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 int attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int detach(struct comedi_device *dev); -static struct comedi_driver cb_pcimdda_driver = { - .driver_name = "cb_pcimdda", - .module = THIS_MODULE, - .attach = attach, - .detach = detach, }; -MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>"); -MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA " - "series. Currently only supports PCIM-DDA06-16 (which " - "also happens to be the only board in this series. :) ) "); -MODULE_LICENSE("GPL"); -static int __devinit cb_pcimdda_driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) +static int cb_pcimdda_ao_winsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - return comedi_pci_auto_config(dev, cb_pcimdda_driver.driver_name); -} - -static void __devexit cb_pcimdda_driver_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver cb_pcimdda_driver_pci_driver = { - .id_table = pci_table, - .probe = &cb_pcimdda_driver_pci_probe, - .remove = __devexit_p(&cb_pcimdda_driver_pci_remove) -}; + 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; + int i; -static int __init cb_pcimdda_driver_init_module(void) -{ - int retval; + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* + * Write the LSB then MSB. + * + * If the simultaneous xfer mode is selected by the + * jumper on the card, a read instruction is needed + * in order to initiate the simultaneous transfer. + * Otherwise, the DAC will be updated when the MSB + * is written. + */ + outb(val & 0x00ff, offset); + outb((val >> 8) & 0x00ff, offset + 1); + } - retval = comedi_driver_register(&cb_pcimdda_driver); - if (retval < 0) - return retval; + /* Cache the last value for readback */ + devpriv->ao_readback[chan] = val; - cb_pcimdda_driver_pci_driver.name = - (char *)cb_pcimdda_driver.driver_name; - return pci_register_driver(&cb_pcimdda_driver_pci_driver); + return insn->n; } -static void __exit cb_pcimdda_driver_cleanup_module(void) +static int cb_pcimdda_ao_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - pci_unregister_driver(&cb_pcimdda_driver_pci_driver); - comedi_driver_unregister(&cb_pcimdda_driver); -} - -module_init(cb_pcimdda_driver_init_module); -module_exit(cb_pcimdda_driver_cleanup_module); + struct cb_pcimdda_private *devpriv = dev->private; + int chan = CR_CHAN(insn->chanspec); + unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan); + int i; -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + for (i = 0; i < insn->n; i++) { + /* Initiate the simultaneous transfer */ + inw(offset); -/*--------------------------------------------------------------------------- - HELPER FUNCTION DECLARATIONS ------------------------------------------------------------------------------*/ + data[i] = devpriv->ao_readback[chan]; + } -/* returns a maxdata value for a given n_bits */ -static inline unsigned int figure_out_maxdata(int bits) -{ - return ((unsigned int)1 << bits) - 1; + return insn->n; } -/* - * Probes for a supported device. - * - * Prerequisite: private be allocated already inside dev - * - * If the device is found, it returns 0 and has the following side effects: - * - * o assigns a struct pci_dev * to dev->private->pci_dev - * o assigns a struct board * to dev->board_ptr - * o sets dev->private->registers - * o sets dev->private->dio_registers - * - * Otherwise, returns a -errno on error - */ -static int probe(struct comedi_device *dev, const struct comedi_devconfig *it); - -/*--------------------------------------------------------------------------- - FUNCTION DEFINITIONS ------------------------------------------------------------------------------*/ - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int attach(struct comedi_device *dev, struct comedi_devconfig *it) +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 err; + int ret; -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - * if this function fails (returns negative) then the private area is - * kfree'd by comedi - */ - if (alloc_private(dev, sizeof(struct board_private_struct)) < 0) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; -/* - * 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. - */ - err = probe(dev, it); - if (err) - return err; + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 3); -/* Output some info */ - printk("comedi%d: %s: ", dev->minor, thisboard->name); - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + s = &dev->subdevices[0]; /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = thisboard->ao_chans; - s->maxdata = figure_out_maxdata(thisboard->ao_bits); - /* this is hard-coded here */ - if (it->options[2]) - s->range_table = &range_bipolar10; - else - s->range_table = &range_bipolar5; - s->insn_write = &ao_winsn; - s->insn_read = &ao_rinsn; - - s = dev->subdevices + 1; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + 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 = &dev->subdevices[1]; /* digital i/o subdevice */ - if (thisboard->dio_chans) { - switch (thisboard->dio_method) { - case DIO_8255: - /* this is a straight 8255, so register us with the 8255 driver */ - subdev_8255_init(dev, s, NULL, devpriv->dio_registers); - devpriv->attached_to_8255 = 1; - break; - case DIO_INTERNAL: - default: - printk("DIO_INTERNAL not implemented yet!\n"); - return -ENXIO; - break; - } - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - devpriv->attached_successfully = 1; - - printk("attached\n"); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int detach(struct comedi_device *dev) -{ - if (devpriv) { - - if (dev->subdevices && devpriv->attached_to_8255) { - /* de-register us from the 8255 driver */ - subdev_8255_cleanup(dev, dev->subdevices + 2); - devpriv->attached_to_8255 = 0; - } - - if (devpriv->pci_dev) { - if (devpriv->registers) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - - if (devpriv->attached_successfully && thisboard) - printk("comedi%d: %s: detached\n", dev->minor, - thisboard->name); - - } + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + PCIMDDA_8255_BASE_REG); + if (ret) + return ret; return 0; } -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i; - int chan = CR_CHAN(insn->chanspec); - unsigned long offset = devpriv->registers + chan * 2; - - /* 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++) { - /* first, load the low byte */ - outb((char)(data[i] & 0x00ff), offset); - /* next, write the high byte -- only after this is written is - the channel voltage updated in the DAC, unless - we're in simultaneous xfer mode (jumper on card) - then a rinsn is necessary to actually update the DAC -- - see ao_rinsn() below... */ - outb((char)(data[i] >> 8 & 0x00ff), offset + 1); - - /* for testing only.. the actual rinsn SHOULD do an inw! - (see the stuff about simultaneous XFER mode on this board) */ - 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. +static struct comedi_driver cb_pcimdda_driver = { + .driver_name = "cb_pcimdda", + .module = THIS_MODULE, + .auto_attach = cb_pcimdda_auto_attach, + .detach = comedi_pci_disable, +}; - Usually this means copying a value stored in devpriv->ao_readback. - However, since this board has this jumper setting called "Simultaneous - Xfer mode" (off by default), we will support it. Simultaneaous xfer - mode is accomplished by loading ALL the values you want for AO in all the - channels, then READing off one of the AO registers to initiate the - instantaneous simultaneous update of all DAC outputs, which makes - all AO channels update simultaneously. This is useful for some control - applications, I would imagine. -*/ -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int cb_pcimdda_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) { - inw(devpriv->registers + chan * 2); - /* should I set data[i] to the result of the actual read on the register - or the cached unsigned int in devpriv->ao_readback[]? */ - data[i] = devpriv->ao_readback[chan]; - } - - return i; + return comedi_pci_auto_config(dev, &cb_pcimdda_driver, + id->driver_data); } -/*--------------------------------------------------------------------------- - HELPER FUNCTION DEFINITIONS ------------------------------------------------------------------------------*/ +static const struct pci_device_id cb_pcimdda_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_ID_PCIM_DDA06_16) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, cb_pcimdda_pci_table); -/* - * Probes for a supported device. - * - * Prerequisite: private be allocated already inside dev - * - * If the device is found, it returns 0 and has the following side effects: - * - * o assigns a struct pci_dev * to dev->private->pci_dev - * o assigns a struct board * to dev->board_ptr - * o sets dev->private->registers - * o sets dev->private->dio_registers - * - * Otherwise, returns a -errno on error - */ -static int probe(struct comedi_device *dev, const struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int index; - unsigned long registers; - - for_each_pci_dev(pcidev) { - /* is it not a computer boards card? */ - if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) - continue; - /* loop through cards supported by this driver */ - for (index = 0; index < ARRAY_SIZE(boards); index++) { - if (boards[index].device_id != pcidev->device) - continue; - /* was a particular bus/slot requested? */ - if (it->options[0] || it->options[1]) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - /* found ! */ - - devpriv->pci_dev = pcidev; - dev->board_ptr = boards + index; - if (comedi_pci_enable(pcidev, thisboard->name)) { - printk - ("cb_pcimdda: Failed to enable PCI device and request regions\n"); - return -EIO; - } - registers = - pci_resource_start(devpriv->pci_dev, - REGS_BADRINDEX); - devpriv->registers = registers; - devpriv->dio_registers - = devpriv->registers + thisboard->dio_offset; - return 0; - } - } +static struct pci_driver cb_pcimdda_driver_pci_driver = { + .name = "cb_pcimdda", + .id_table = cb_pcimdda_pci_table, + .probe = cb_pcimdda_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(cb_pcimdda_driver, cb_pcimdda_driver_pci_driver); - printk("cb_pcimdda: No supported ComputerBoards/MeasurementComputing " - "card found at the requested position\n"); - return -ENODEV; -} +MODULE_AUTHOR("Calin A. Culianu <calin@rtlab.org>"); +MODULE_DESCRIPTION("Comedi low-level driver for the Computerboards PCIM-DDA " + "series. Currently only supports PCIM-DDA06-16 (which " + "also happens to be the only board in this series. :) ) "); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index d8aefb23d6b..8450c99af8b 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -1,310 +1,131 @@ /* - comedi/drivers/comedi_bond.c - A Comedi driver to 'bond' or merge multiple drivers and devices as one. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - Copyright (C) 2005 Calin A. Culianu <calin@ajvar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * comedi_bond.c + * A Comedi driver to 'bond' or merge multiple drivers and devices as one. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * Copyright (C) 2005 Calin A. Culianu <calin@ajvar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -*/ /* -Driver: comedi_bond -Description: A driver to 'bond' (merge) multiple subdevices from multiple - devices together as one. -Devices: -Author: ds -Updated: Mon, 10 Oct 00:18:25 -0500 -Status: works - -This driver allows you to 'bond' (merge) multiple comedi subdevices -(coming from possibly difference boards and/or drivers) together. For -example, if you had a board with 2 different DIO subdevices, and -another with 1 DIO subdevice, you could 'bond' them with this driver -so that they look like one big fat DIO subdevice. This makes writing -applications slightly easier as you don't have to worry about managing -different subdevices in the application -- you just worry about -indexing one linear array of channel id's. - -Right now only DIO subdevices are supported as that's the personal itch -I am scratching with this driver. If you want to add support for AI and AO -subdevs, go right on ahead and do so! - -Commands aren't supported -- although it would be cool if they were. - -Configuration Options: - List of comedi-minors to bond. All subdevices of the same type - within each minor will be concatenated together in the order given here. -*/ + * Driver: comedi_bond + * Description: A driver to 'bond' (merge) multiple subdevices from multiple + * devices together as one. + * Devices: + * Author: ds + * Updated: Mon, 10 Oct 00:18:25 -0500 + * Status: works + * + * This driver allows you to 'bond' (merge) multiple comedi subdevices + * (coming from possibly difference boards and/or drivers) together. For + * example, if you had a board with 2 different DIO subdevices, and + * another with 1 DIO subdevice, you could 'bond' them with this driver + * so that they look like one big fat DIO subdevice. This makes writing + * applications slightly easier as you don't have to worry about managing + * different subdevices in the application -- you just worry about + * indexing one linear array of channel id's. + * + * Right now only DIO subdevices are supported as that's the personal itch + * I am scratching with this driver. If you want to add support for AI and AO + * subdevs, go right on ahead and do so! + * + * Commands aren't supported -- although it would be cool if they were. + * + * Configuration Options: + * List of comedi-minors to bond. All subdevices of the same type + * within each minor will be concatenated together in the order given here. + */ +#include <linux/module.h> #include <linux/string.h> #include <linux/slab.h> #include "../comedi.h" #include "../comedilib.h" #include "../comedidev.h" -/* The maxiumum number of channels per subdevice. */ -#define MAX_CHANS 256 - -#define MODULE_NAME "comedi_bond" -MODULE_LICENSE("GPL"); -#ifndef STR -# define STR1(x) #x -# define STR(x) STR1(x) -#endif - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful" - "only to developers."); - -#define LOG_MSG(x...) printk(KERN_INFO MODULE_NAME": "x) -#define DEBUG(x...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG MODULE_NAME": DEBUG: "x); \ - } while (0) -#define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x) -#define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x) -MODULE_AUTHOR("Calin A. Culianu"); -MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI " - "devices together as one. In the words of John Lennon: " - "'And the world will live as one...'"); - -/* - * 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. - */ -struct BondingBoard { - const char *name; -}; - -static const struct BondingBoard bondingBoards[] = { - { - .name = MODULE_NAME, - }, -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct BondingBoard *)dev->board_ptr) - -struct BondedDevice { +struct bonded_device { struct comedi_device *dev; unsigned minor; unsigned subdev; - unsigned subdev_type; unsigned nchans; - unsigned chanid_offset; /* The offset into our unified linear - channel-id's of chanid 0 on this - subdevice. */ }; -/* 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 Private { +struct comedi_bond_private { # define MAX_BOARD_NAME 256 char name[MAX_BOARD_NAME]; - struct BondedDevice **devs; + struct bonded_device **devs; unsigned ndevs; - struct BondedDevice *chanIdDevMap[MAX_CHANS]; unsigned nchans; }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct Private *)dev->private) - -/* - * 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 int bonding_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int bonding_detach(struct comedi_device *dev); -/** Build Private array of all devices.. */ -static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it); -static void doDevUnconfig(struct comedi_device *dev); -/* Ugly implementation of realloc that always copies memory around -- I'm lazy, - * what can I say? I like to do wasteful memcopies.. :) */ -static void *Realloc(const void *ptr, size_t len, size_t old_len); - -static struct comedi_driver driver_bonding = { - .driver_name = MODULE_NAME, - .module = THIS_MODULE, - .attach = bonding_attach, - .detach = bonding_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 = &bondingBoards[0].name, - .offset = sizeof(struct BondingBoard), - .num_names = ARRAY_SIZE(bondingBoards), -}; - -static int bonding_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int bonding_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int bonding_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - - LOG_MSG("comedi%d\n", dev->minor); - - /* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct Private)) < 0) - return -ENOMEM; - - /* - * Setup our bonding from config params.. sets up our Private struct.. - */ - if (!doDevConfig(dev, it)) - return -EINVAL; - - /* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = devpriv->name; - - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = devpriv->nchans; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = bonding_dio_insn_bits; - s->insn_config = bonding_dio_insn_config; - - LOG_MSG("attached with %u DIO channels coming from %u different " - "subdevices all bonded together. " - "John Lennon would be proud!\n", - devpriv->nchans, devpriv->ndevs); - - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int bonding_detach(struct comedi_device *dev) -{ - LOG_MSG("comedi%d: remove\n", dev->minor); - doDevUnconfig(dev); - return 0; -} - -/* 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 bonding_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { -#define LSAMPL_BITS (sizeof(unsigned int)*8) - unsigned nchans = LSAMPL_BITS, num_done = 0, i; - if (insn->n != 2) - return -EINVAL; - - if (devpriv->nchans < nchans) - nchans = devpriv->nchans; - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - for (i = 0; num_done < nchans && i < devpriv->ndevs; ++i) { - struct BondedDevice *bdev = devpriv->devs[i]; - /* Grab the channel mask and data of only the bits corresponding - to this subdevice.. need to shift them to zero position of - course. */ - /* Bits corresponding to this subdev. */ - unsigned int subdevMask = ((1 << bdev->nchans) - 1); - unsigned int writeMask, dataBits; - - /* Argh, we have >= LSAMPL_BITS chans.. take all bits */ - if (bdev->nchans >= LSAMPL_BITS) - subdevMask = (unsigned int)(-1); - - writeMask = (data[0] >> num_done) & subdevMask; - dataBits = (data[1] >> num_done) & subdevMask; - - /* Read/Write the new digital lines */ - if (comedi_dio_bitfield(bdev->dev, bdev->subdev, writeMask, - &dataBits) != 2) - return -EINVAL; - - /* Make room for the new bits in data[1], the return value */ - data[1] &= ~(subdevMask << num_done); - /* Put the bits in the return value */ - data[1] |= (dataBits & subdevMask) << num_done; - /* Save the new bits to the saved state.. */ - s->state = data[1]; - - num_done += bdev->nchans; - } + struct comedi_bond_private *devpriv = dev->private; + unsigned int n_left, n_done, base_chan; + unsigned int write_mask, data_bits; + struct bonded_device **devs; + + write_mask = data[0]; + data_bits = data[1]; + base_chan = CR_CHAN(insn->chanspec); + /* do a maximum of 32 channels, starting from base_chan. */ + n_left = devpriv->nchans - base_chan; + if (n_left > 32) + n_left = 32; + + n_done = 0; + devs = devpriv->devs; + do { + struct bonded_device *bdev = *devs++; + + if (base_chan < bdev->nchans) { + /* base channel falls within bonded device */ + unsigned int b_chans, b_mask, b_write_mask, b_data_bits; + int ret; + + /* + * Get num channels to do for bonded device and set + * up mask and data bits for bonded device. + */ + b_chans = bdev->nchans - base_chan; + if (b_chans > n_left) + b_chans = n_left; + b_mask = (1U << b_chans) - 1; + b_write_mask = (write_mask >> n_done) & b_mask; + b_data_bits = (data_bits >> n_done) & b_mask; + /* Read/Write the new digital lines. */ + ret = comedi_dio_bitfield2(bdev->dev, bdev->subdev, + b_write_mask, &b_data_bits, + base_chan); + if (ret < 0) + return ret; + /* Place read bits into data[1]. */ + data[1] &= ~(b_mask << n_done); + data[1] |= (b_data_bits & b_mask) << n_done; + /* + * Set up for following bonded device (if still have + * channels to read/write). + */ + base_chan = 0; + n_done += b_chans; + n_left -= b_chans; + } else { + /* Skip bonded devices before base channel. */ + base_chan -= bdev->nchans; + } + } while (n_left); return insn->n; } @@ -313,94 +134,92 @@ static int bonding_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits; - unsigned int io; - struct BondedDevice *bdev; + struct comedi_bond_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int ret; + struct bonded_device *bdev; + struct bonded_device **devs; - if (chan < 0 || chan >= devpriv->nchans) - return -EINVAL; - bdev = devpriv->chanIdDevMap[chan]; + /* + * Locate bonded subdevice and adjust channel. + */ + devs = devpriv->devs; + for (bdev = *devs++; chan >= bdev->nchans; bdev = *devs++) + chan -= bdev->nchans; - /* The input or output configuration of each digital line is + /* + * The input or output configuration of each digital line is * configured by a special insn_config instruction. chanspec * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ + * configuration instruction INSN_CONFIG_DIO_OUTPUT, + * INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_QUERY. + * + * Note that INSN_CONFIG_DIO_OUTPUT == COMEDI_OUTPUT, + * and INSN_CONFIG_DIO_INPUT == COMEDI_INPUT. This is deliberate ;) + */ switch (data[0]) { case INSN_CONFIG_DIO_OUTPUT: - io = COMEDI_OUTPUT; /* is this really necessary? */ - io_bits |= 1 << chan; - break; case INSN_CONFIG_DIO_INPUT: - io = COMEDI_INPUT; /* is this really necessary? */ - io_bits &= ~(1 << chan); + ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, data[0]); break; case INSN_CONFIG_DIO_QUERY: - data[1] = - (io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; + ret = comedi_dio_get_config(bdev->dev, bdev->subdev, chan, + &data[1]); break; default: - return -EINVAL; + ret = -EINVAL; break; } - /* 'real' channel id for this subdev.. */ - chan -= bdev->chanid_offset; - ret = comedi_dio_config(bdev->dev, bdev->subdev, chan, io); - if (ret != 1) - return -EINVAL; - /* Finally, save the new io_bits values since we didn't get - an error above. */ - s->io_bits = io_bits; - return insn->n; + if (ret >= 0) + ret = insn->n; + return ret; } -static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen) -{ - void *newmem = kmalloc(newlen, GFP_KERNEL); - - if (newmem && oldmem) - memcpy(newmem, oldmem, min(oldlen, newlen)); - kfree(oldmem); - return newmem; -} - -static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) +static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it) { + struct comedi_bond_private *devpriv = dev->private; + DECLARE_BITMAP(devs_opened, COMEDI_NUM_BOARD_MINORS); int i; - struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS]; - memset(devs_opened, 0, sizeof(devs_opened)); + memset(&devs_opened, 0, sizeof(devs_opened)); devpriv->name[0] = 0; - /* Loop through all comedi devices specified on the command-line, - building our device list */ + /* + * Loop through all comedi devices specified on the command-line, + * building our device list. + */ for (i = 0; i < COMEDI_NDEVCONFOPTS && (!i || it->options[i]); ++i) { - char file[] = "/dev/comediXXXXXX"; + char file[sizeof("/dev/comediXXXXXX")]; int minor = it->options[i]; struct comedi_device *d; - int sdev = -1, nchans, tmp; - struct BondedDevice *bdev = NULL; + int sdev = -1, nchans; + struct bonded_device *bdev; + struct bonded_device **devs; if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) { - ERROR("Minor %d is invalid!\n", minor); - return 0; + dev_err(dev->class_dev, + "Minor %d is invalid!\n", minor); + return -EINVAL; } if (minor == dev->minor) { - ERROR("Cannot bond this driver to itself!\n"); - return 0; + dev_err(dev->class_dev, + "Cannot bond this driver to itself!\n"); + return -EINVAL; } - if (devs_opened[minor]) { - ERROR("Minor %d specified more than once!\n", minor); - return 0; + if (test_and_set_bit(minor, devs_opened)) { + dev_err(dev->class_dev, + "Minor %d specified more than once!\n", minor); + return -EINVAL; } - snprintf(file, sizeof(file), "/dev/comedi%u", minor); + snprintf(file, sizeof(file), "/dev/comedi%d", minor); file[sizeof(file) - 1] = 0; - d = devs_opened[minor] = comedi_open(file); + d = comedi_open(file); if (!d) { - ERROR("Minor %u could not be opened\n", minor); - return 0; + dev_err(dev->class_dev, + "Minor %u could not be opened\n", minor); + return -ENODEV; } /* Do DIO, as that's all we support now.. */ @@ -408,49 +227,45 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) sdev + 1)) > -1) { nchans = comedi_get_n_channels(d, sdev); if (nchans <= 0) { - ERROR("comedi_get_n_channels() returned %d " - "on minor %u subdev %d!\n", - nchans, minor, sdev); - return 0; + dev_err(dev->class_dev, + "comedi_get_n_channels() returned %d on minor %u subdev %d!\n", + nchans, minor, sdev); + return -EINVAL; } bdev = kmalloc(sizeof(*bdev), GFP_KERNEL); - if (!bdev) { - ERROR("Out of memory.\n"); - return 0; - } + if (!bdev) + return -ENOMEM; + bdev->dev = d; bdev->minor = minor; bdev->subdev = sdev; - bdev->subdev_type = COMEDI_SUBD_DIO; bdev->nchans = nchans; - bdev->chanid_offset = devpriv->nchans; + devpriv->nchans += nchans; - /* map channel id's to BondedDevice * pointer.. */ - while (nchans--) - devpriv->chanIdDevMap[devpriv->nchans++] = bdev; - - /* Now put bdev pointer at end of devpriv->devs array - * list.. */ + /* + * Now put bdev pointer at end of devpriv->devs array + * list.. + */ /* ergh.. ugly.. we need to realloc :( */ - tmp = devpriv->ndevs * sizeof(bdev); - devpriv->devs = - Realloc(devpriv->devs, - ++devpriv->ndevs * sizeof(bdev), tmp); - if (!devpriv->devs) { - ERROR("Could not allocate memory. " - "Out of memory?"); - return 0; + devs = krealloc(devpriv->devs, + (devpriv->ndevs + 1) * sizeof(*devs), + GFP_KERNEL); + if (!devs) { + dev_err(dev->class_dev, + "Could not allocate memory. Out of memory?\n"); + kfree(bdev); + return -ENOMEM; } - - devpriv->devs[devpriv->ndevs - 1] = bdev; + devpriv->devs = devs; + devpriv->devs[devpriv->ndevs++] = bdev; { - /** Append dev:subdev to devpriv->name */ + /* Append dev:subdev to devpriv->name */ char buf[20]; int left = MAX_BOARD_NAME - strlen(devpriv->name) - 1; - snprintf(buf, sizeof(buf), "%d:%d ", dev->minor, - bdev->subdev); + snprintf(buf, sizeof(buf), "%u:%u ", + bdev->minor, bdev->subdev); buf[sizeof(buf) - 1] = 0; strncat(devpriv->name, buf, left); } @@ -459,46 +274,85 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) } if (!devpriv->nchans) { - ERROR("No channels found!\n"); - return 0; + dev_err(dev->class_dev, "No channels found!\n"); + return -EINVAL; } - return 1; + return 0; +} + +static int bonding_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct comedi_bond_private *devpriv; + struct comedi_subdevice *s; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + /* + * Setup our bonding from config params.. sets up our private struct.. + */ + ret = do_dev_config(dev, it); + if (ret) + return ret; + + dev->board_name = devpriv->name; + + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = devpriv->nchans; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = bonding_dio_insn_bits; + s->insn_config = bonding_dio_insn_config; + + dev_info(dev->class_dev, + "%s: %s attached, %u channels from %u devices\n", + dev->driver->driver_name, dev->board_name, + devpriv->nchans, devpriv->ndevs); + + return 0; } -static void doDevUnconfig(struct comedi_device *dev) +static void bonding_detach(struct comedi_device *dev) { - unsigned long devs_closed = 0; + struct comedi_bond_private *devpriv = dev->private; + + if (devpriv && devpriv->devs) { + DECLARE_BITMAP(devs_closed, COMEDI_NUM_BOARD_MINORS); - if (devpriv) { - while (devpriv->ndevs-- && devpriv->devs) { - struct BondedDevice *bdev; + memset(&devs_closed, 0, sizeof(devs_closed)); + while (devpriv->ndevs--) { + struct bonded_device *bdev; bdev = devpriv->devs[devpriv->ndevs]; if (!bdev) continue; - if (!(devs_closed & (0x1 << bdev->minor))) { + if (!test_and_set_bit(bdev->minor, devs_closed)) comedi_close(bdev->dev); - devs_closed |= (0x1 << bdev->minor); - } kfree(bdev); } kfree(devpriv->devs); devpriv->devs = NULL; - kfree(devpriv); - dev->private = NULL; } } -static int __init init(void) -{ - return comedi_driver_register(&driver_bonding); -} - -static void __exit cleanup(void) -{ - comedi_driver_unregister(&driver_bonding); -} +static struct comedi_driver bonding_driver = { + .driver_name = "comedi_bond", + .module = THIS_MODULE, + .attach = bonding_attach, + .detach = bonding_detach, +}; +module_comedi_driver(bonding_driver); -module_init(init); -module_exit(cleanup); +MODULE_AUTHOR("Calin A. Culianu"); +MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI devices together as one."); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_fc.c b/drivers/staging/comedi/drivers/comedi_fc.c index 63be619dd60..c33c3e5680a 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.c +++ b/drivers/staging/comedi/drivers/comedi_fc.c @@ -1,38 +1,53 @@ /* - comedi/drivers/comedi_fc.c - - This is a place for code driver writers wish to share between - two or more drivers. fc is short - for frank-common. - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ - + * comedi_fc.c + * This is a place for code driver writers wish to share between + * two or more drivers. fc is short for frank-common. + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> #include "../comedidev.h" #include "comedi_fc.h" -static void increment_scan_progress(struct comedi_subdevice *subd, - unsigned int num_bytes) +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *s) +{ + struct comedi_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 = subd->async; - unsigned int scan_length = cfc_bytes_per_scan(subd); + 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) { @@ -40,80 +55,78 @@ static void increment_scan_progress(struct comedi_subdevice *subd, async->events |= COMEDI_CB_EOS; } } +EXPORT_SYMBOL_GPL(cfc_inc_scan_progress); /* Writes an array of data points to comedi's buffer */ -unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, +unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *s, void *data, unsigned int num_bytes) { - struct comedi_async *async = subd->async; + struct comedi_async *async = s->async; unsigned int retval; if (num_bytes == 0) return 0; - retval = comedi_buf_write_alloc(async, num_bytes); + retval = comedi_buf_write_alloc(s, num_bytes); if (retval != num_bytes) { - printk(KERN_WARNING "comedi: buffer overrun\n"); + dev_warn(s->device->class_dev, "buffer overrun\n"); async->events |= COMEDI_CB_OVERFLOW; return 0; } - comedi_buf_memcpy_to(async, 0, data, num_bytes); - comedi_buf_write_free(async, num_bytes); - increment_scan_progress(subd, num_bytes); + comedi_buf_memcpy_to(s, 0, data, num_bytes); + comedi_buf_write_free(s, num_bytes); + cfc_inc_scan_progress(s, num_bytes); async->events |= COMEDI_CB_BLOCK; return num_bytes; } -EXPORT_SYMBOL(cfc_write_array_to_buffer); +EXPORT_SYMBOL_GPL(cfc_write_array_to_buffer); -unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, +unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *s, void *data, unsigned int num_bytes) { - struct comedi_async *async = subd->async; - if (num_bytes == 0) return 0; - num_bytes = comedi_buf_read_alloc(async, num_bytes); - comedi_buf_memcpy_from(async, 0, data, num_bytes); - comedi_buf_read_free(async, num_bytes); - increment_scan_progress(subd, num_bytes); - async->events |= COMEDI_CB_BLOCK; + num_bytes = comedi_buf_read_alloc(s, num_bytes); + comedi_buf_memcpy_from(s, 0, data, num_bytes); + comedi_buf_read_free(s, num_bytes); + cfc_inc_scan_progress(s, num_bytes); + s->async->events |= COMEDI_CB_BLOCK; return num_bytes; } -EXPORT_SYMBOL(cfc_read_array_from_buffer); +EXPORT_SYMBOL_GPL(cfc_read_array_from_buffer); unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *subd) + struct comedi_subdevice *s) { - unsigned int events = subd->async->events; + unsigned int events = s->async->events; if (events == 0) return events; if (events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW)) - subd->cancel(dev, subd); + s->cancel(dev, s); - comedi_event(dev, subd); + comedi_event(dev, s); return events; } -EXPORT_SYMBOL(cfc_handle_events); - -MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); -MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); -MODULE_LICENSE("GPL"); +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_init(comedi_fc_init_module); module_exit(comedi_fc_cleanup_module); + +MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); +MODULE_DESCRIPTION("Shared functions for Comedi low-level drivers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index 4b2cfd32799..541b9371d3d 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -1,76 +1,127 @@ /* - comedi_fc.h - - This is a place for code driver writers wish to share between - two or more drivers. These functions are meant to be used only - by drivers, they are NOT part of the kcomedilib API! - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2002 Frank Mori Hess - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ + * comedi_fc.h + * This is a place for code driver writers wish to share between + * two or more drivers. These functions are meant to be used only + * by drivers, they are NOT part of the kcomedilib API! + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2002 Frank Mori Hess + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #ifndef _COMEDI_FC_H #define _COMEDI_FC_H #include "../comedidev.h" +unsigned int cfc_bytes_per_scan(struct comedi_subdevice *); +void cfc_inc_scan_progress(struct comedi_subdevice *, unsigned int num_bytes); + /* Writes an array of data points to comedi's buffer */ -extern unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *subd, - void *data, - unsigned int num_bytes); +unsigned int cfc_write_array_to_buffer(struct comedi_subdevice *, + void *data, unsigned int num_bytes); -static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *subd, - short data) +static inline unsigned int cfc_write_to_buffer(struct comedi_subdevice *s, + unsigned short data) { - return cfc_write_array_to_buffer(subd, &data, sizeof(data)); + return cfc_write_array_to_buffer(s, &data, sizeof(data)); }; -static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice - *subd, unsigned int data) +static inline unsigned int cfc_write_long_to_buffer(struct comedi_subdevice *s, + unsigned int data) { - return cfc_write_array_to_buffer(subd, &data, sizeof(data)); + return cfc_write_array_to_buffer(s, &data, sizeof(data)); }; -extern unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *subd, - void *data, - unsigned int num_bytes); +unsigned int cfc_read_array_from_buffer(struct comedi_subdevice *, + void *data, unsigned int num_bytes); + +unsigned int cfc_handle_events(struct comedi_device *, + struct comedi_subdevice *); + +/** + * cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source + * @src: pointer to the trigger source to validate + * @flags: bitmask of valid TRIG_* for the trigger + * + * This is used in "step 1" of the do_cmdtest functions of comedi drivers + * to vaildate the comedi_cmd triggers. The mask of the @src against the + * @flags allows the userspace comedilib to pass all the comedi_cmd + * triggers as TRIG_ANY and get back a bitmask of the valid trigger sources. + */ +static inline int cfc_check_trigger_src(unsigned int *src, unsigned int flags) +{ + unsigned int orig_src = *src; -extern unsigned int cfc_handle_events(struct comedi_device *dev, - struct comedi_subdevice *subd); + *src = orig_src & flags; + if (*src == TRIG_INVALID || *src != orig_src) + return -EINVAL; + return 0; +} -static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *subd) +/** + * cfc_check_trigger_is_unique() - make sure a trigger source is unique + * @src: the trigger source to check + */ +static inline int cfc_check_trigger_is_unique(unsigned int src) { - int num_samples; - int bits_per_sample; + /* this test is true if more than one _src bit is set */ + if ((src & (src - 1)) != 0) + return -EINVAL; + return 0; +} - switch (subd->type) { - case COMEDI_SUBD_DI: - case COMEDI_SUBD_DO: - case COMEDI_SUBD_DIO: - bits_per_sample = 8 * bytes_per_sample(subd); - num_samples = (subd->async->cmd.chanlist_len + - bits_per_sample - 1) / bits_per_sample; - break; - default: - num_samples = subd->async->cmd.chanlist_len; - break; +/** + * cfc_check_trigger_arg_is() - trivially validate a trigger argument + * @arg: pointer to the trigger arg to validate + * @val: the value the argument should be + */ +static inline int cfc_check_trigger_arg_is(unsigned int *arg, unsigned int val) +{ + if (*arg != val) { + *arg = val; + return -EINVAL; + } + return 0; +} + +/** + * cfc_check_trigger_arg_min() - trivially validate a trigger argument + * @arg: pointer to the trigger arg to validate + * @val: the minimum value the argument should be + */ +static inline int cfc_check_trigger_arg_min(unsigned int *arg, + unsigned int val) +{ + if (*arg < val) { + *arg = val; + return -EINVAL; + } + return 0; +} + +/** + * cfc_check_trigger_arg_max() - trivially validate a trigger argument + * @arg: pointer to the trigger arg to validate + * @val: the maximum value the argument should be + */ +static inline int cfc_check_trigger_arg_max(unsigned int *arg, + unsigned int val) +{ + if (*arg > val) { + *arg = val; + return -EINVAL; } - return num_samples * bytes_per_sample(subd); + return 0; } #endif /* _COMEDI_FC_H */ diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index 21d834dd92b..a4274869235 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -1,195 +1,156 @@ /* - comedi/drivers/comedi_parport.c - hardware driver for standard parallel port - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998,2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * comedi_parport.c + * Comedi driver for standard parallel port + * + * For more information see: + * http://retired.beyondlogic.org/spp/parallel.htm + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998,2001 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -*/ -/* -Driver: comedi_parport -Description: Standard PC parallel port -Author: ds -Status: works in immediate mode -Devices: [standard] parallel port (comedi_parport) -Updated: Tue, 30 Apr 2002 21:11:45 -0700 - -A cheap and easy way to get a few more digital I/O lines. Steal -additional parallel ports from old computers or your neighbors' -computers. - -Option list: - 0: I/O port base for the parallel port. - 1: IRQ - -Parallel Port Lines: - -pin subdev chan aka ---- ------ ---- --- -1 2 0 strobe -2 0 0 data 0 -3 0 1 data 1 -4 0 2 data 2 -5 0 3 data 3 -6 0 4 data 4 -7 0 5 data 5 -8 0 6 data 6 -9 0 7 data 7 -10 1 3 acknowledge -11 1 4 busy -12 1 2 output -13 1 1 printer selected -14 2 1 auto LF -15 1 0 error -16 2 2 init -17 2 3 select printer -18-25 ground - -Notes: - -Subdevices 0 is digital I/O, subdevice 1 is digital input, and -subdevice 2 is digital output. Unlike other Comedi devices, -subdevice 0 defaults to output. - -Pins 13 and 14 are inverted once by Comedi and once by the -hardware, thus cancelling the effect. - -Pin 1 is a strobe, thus acts like one. There's no way in software -to change this, at least on a standard parallel port. - -Subdevice 3 pretends to be a digital input subdevice, but it always -returns 0 when read. However, if you run a command with -scan_begin_src=TRIG_EXT, it uses pin 10 as a external triggering -pin, which can be used to wake up tasks. -*/ /* - see http://www.beyondlogic.org/ for information. - or http://www.linux-magazin.de/ausgabe/1999/10/IO/io.html + * Driver: comedi_parport + * Description: Standard PC parallel port + * Author: ds + * Status: works in immediate mode + * Devices: (standard) parallel port [comedi_parport] + * Updated: Tue, 30 Apr 2002 21:11:45 -0700 + * + * A cheap and easy way to get a few more digital I/O lines. Steal + * additional parallel ports from old computers or your neighbors' + * computers. + * + * Option list: + * 0: I/O port base for the parallel port. + * 1: IRQ (optional) + * + * Parallel Port Lines: + * + * pin subdev chan type name + * ----- ------ ---- ---- -------------- + * 1 2 0 DO strobe + * 2 0 0 DIO data 0 + * 3 0 1 DIO data 1 + * 4 0 2 DIO data 2 + * 5 0 3 DIO data 3 + * 6 0 4 DIO data 4 + * 7 0 5 DIO data 5 + * 8 0 6 DIO data 6 + * 9 0 7 DIO data 7 + * 10 1 3 DI ack + * 11 1 4 DI busy + * 12 1 2 DI paper out + * 13 1 1 DI select in + * 14 2 1 DO auto LF + * 15 1 0 DI error + * 16 2 2 DO init + * 17 2 3 DO select printer + * 18-25 ground + * + * When an IRQ is configured subdevice 3 pretends to be a digital + * input subdevice, but it always returns 0 when read. However, if + * you run a command with scan_begin_src=TRIG_EXT, it uses pin 10 + * as a external trigger, which can be used to wake up tasks. */ -#include "../comedidev.h" +#include <linux/module.h> #include <linux/interrupt.h> -#include <linux/ioport.h> -#define PARPORT_SIZE 3 - -#define PARPORT_A 0 -#define PARPORT_B 1 -#define PARPORT_C 2 - -static int parport_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int parport_detach(struct comedi_device *dev); -static struct comedi_driver driver_parport = { - .driver_name = "comedi_parport", - .module = THIS_MODULE, - .attach = parport_attach, - .detach = parport_detach, -}; +#include "../comedidev.h" -static int __init driver_parport_init_module(void) -{ - return comedi_driver_register(&driver_parport); -} +#include "comedi_fc.h" -static void __exit driver_parport_cleanup_module(void) +/* + * Register map + */ +#define PARPORT_DATA_REG 0x00 +#define PARPORT_STATUS_REG 0x01 +#define PARPORT_CTRL_REG 0x02 +#define PARPORT_CTRL_IRQ_ENA (1 << 4) +#define PARPORT_CTRL_BIDIR_ENA (1 << 5) + +static int parport_data_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - comedi_driver_unregister(&driver_parport); -} + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + PARPORT_DATA_REG); -module_init(driver_parport_init_module); -module_exit(driver_parport_cleanup_module); + data[1] = inb(dev->iobase + PARPORT_DATA_REG); -struct parport_private { - unsigned int a_data; - unsigned int c_data; - int enable_irq; -}; -#define devpriv ((struct parport_private *)(dev->private)) + return insn->n; +} -static int parport_insn_a(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_data_reg_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - devpriv->a_data &= ~data[0]; - devpriv->a_data |= (data[0] & data[1]); + unsigned int ctrl; + int ret; - outb(devpriv->a_data, dev->iobase + PARPORT_A); - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0xff); + if (ret) + return ret; - data[1] = inb(dev->iobase + PARPORT_A); + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + if (s->io_bits) + ctrl &= ~PARPORT_CTRL_BIDIR_ENA; + else + ctrl |= PARPORT_CTRL_BIDIR_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); - return 2; + return insn->n; } -static int parport_insn_config_a(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_status_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->io_bits = 0xff; - devpriv->c_data &= ~(1 << 5); - } else { - s->io_bits = 0; - devpriv->c_data |= (1 << 5); - } - outb(devpriv->c_data, dev->iobase + PARPORT_C); + data[1] = inb(dev->iobase + PARPORT_STATUS_REG) >> 3; - return 1; + return insn->n; } -static int parport_insn_b(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_ctrl_reg_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - /* should writes be ignored? */ - /* anyone??? */ - } - - data[1] = (inb(dev->iobase + PARPORT_B) >> 3); + unsigned int ctrl; - return 2; -} - -static int parport_insn_c(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[0] &= 0x0f; - if (data[0]) { - devpriv->c_data &= ~data[0]; - devpriv->c_data |= (data[0] & data[1]); - - outb(devpriv->c_data, dev->iobase + PARPORT_C); + if (comedi_dio_update_state(s, data)) { + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl &= (PARPORT_CTRL_IRQ_ENA | PARPORT_CTRL_BIDIR_ENA); + ctrl |= s->state; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); } - data[1] = devpriv->c_data & 0xf; + data[1] = s->state; - return 2; + return insn->n; } -static int parport_intr_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int parport_intr_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n < 1) - return -EINVAL; - data[1] = 0; - return 2; + return insn->n; } static int parport_intr_cmdtest(struct comedi_device *dev, @@ -197,65 +158,31 @@ static int parport_intr_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1 */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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 2: ignored */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->scan_end_arg != 1) { - cmd->scan_end_arg = 1; - err++; - } - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + 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; @@ -271,10 +198,11 @@ static int parport_intr_cmdtest(struct comedi_device *dev, static int parport_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - devpriv->c_data |= 0x10; - outb(devpriv->c_data, dev->iobase + PARPORT_C); + unsigned int ctrl; - devpriv->enable_irq = 1; + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl |= PARPORT_CTRL_IRQ_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); return 0; } @@ -282,12 +210,11 @@ static int parport_intr_cmd(struct comedi_device *dev, static int parport_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - printk(KERN_DEBUG "parport_intr_cancel()\n"); + unsigned int ctrl; - devpriv->c_data &= ~0x10; - outb(devpriv->c_data, dev->iobase + PARPORT_C); - - devpriv->enable_irq = 0; + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + ctrl &= ~PARPORT_CTRL_IRQ_ENA; + outb(ctrl, dev->iobase + PARPORT_CTRL_REG); return 0; } @@ -295,14 +222,14 @@ static int parport_intr_cancel(struct comedi_device *dev, static irqreturn_t parport_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 3; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int ctrl; - if (!devpriv->enable_irq) { - printk(KERN_ERR "comedi_parport: bogus irq, ignored\n"); + ctrl = inb(dev->iobase + PARPORT_CTRL_REG); + if (!(ctrl & PARPORT_CTRL_IRQ_ENA)) return IRQ_NONE; - } - comedi_buf_put(s->async, 0); + comedi_buf_put(s, 0); s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(dev, s); @@ -312,102 +239,82 @@ static irqreturn_t parport_interrupt(int irq, void *d) static int parport_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int ret; - unsigned int irq; - unsigned long iobase; struct comedi_subdevice *s; + int ret; - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: parport: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, PARPORT_SIZE, "parport (comedi)")) { - printk(KERN_ERR "I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - irq = it->options[1]; - if (irq) { - printk(KERN_INFO " irq=%u", irq); - ret = request_irq(irq, parport_interrupt, 0, "comedi_parport", - dev); - if (ret < 0) { - printk(KERN_ERR " irq not available\n"); - return -EINVAL; - } - dev->irq = irq; + ret = comedi_request_region(dev, it->options[0], 0x03); + if (ret) + return ret; + + if (it->options[1]) { + ret = request_irq(it->options[1], parport_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - dev->board_name = "parport"; - ret = alloc_subdevices(dev, 4); - if (ret < 0) - return ret; - ret = alloc_private(dev, sizeof(struct parport_private)); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, dev->irq ? 4 : 3); + if (ret) return ret; - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_insn_a; - s->insn_config = parport_insn_config_a; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 5; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = parport_insn_b; - - s = dev->subdevices + 2; - 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 = parport_insn_c; - - s = dev->subdevices + 3; - if (irq) { + /* Digial I/O subdevice - Parallel port DATA register */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_data_reg_insn_bits; + s->insn_config = parport_data_reg_insn_config; + + /* Digial Input subdevice - Parallel port STATUS register */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 5; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_status_reg_insn_bits; + + /* Digial Output subdevice - Parallel port CONTROL register */ + s = &dev->subdevices[2]; + 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 = parport_ctrl_reg_insn_bits; + + if (dev->irq) { + /* Digial Input subdevice - Interrupt support */ + s = &dev->subdevices[3]; 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->insn_bits = parport_intr_insn; - s->do_cmdtest = parport_intr_cmdtest; - s->do_cmd = parport_intr_cmd; - s->cancel = parport_intr_cancel; - } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->n_chan = 1; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = parport_intr_insn_bits; + s->len_chanlist = 1; + s->do_cmdtest = parport_intr_cmdtest; + s->do_cmd = parport_intr_cmd; + s->cancel = parport_intr_cancel; } - devpriv->a_data = 0; - outb(devpriv->a_data, dev->iobase + PARPORT_A); - devpriv->c_data = 0; - outb(devpriv->c_data, dev->iobase + PARPORT_C); - - printk(KERN_INFO "\n"); - return 1; -} - -static int parport_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: parport: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, PARPORT_SIZE); - - if (dev->irq) - free_irq(dev->irq, dev); + outb(0, dev->iobase + PARPORT_DATA_REG); + outb(0, dev->iobase + PARPORT_CTRL_REG); return 0; } +static struct comedi_driver parport_driver = { + .driver_name = "comedi_parport", + .module = THIS_MODULE, + .attach = parport_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(parport_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi: Standard parallel port driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_pci.h b/drivers/staging/comedi/drivers/comedi_pci.h deleted file mode 100644 index c14a036a053..00000000000 --- a/drivers/staging/comedi/drivers/comedi_pci.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - comedi/drivers/comedi_pci.h - Various PCI functions for drivers. - - Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/> - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef _COMEDI_PCI_H_ -#define _COMEDI_PCI_H_ - -#include <linux/pci.h> - -/* - * Enable the PCI device and request the regions. - */ -static inline int comedi_pci_enable(struct pci_dev *pdev, const char *res_name) -{ - int rc; - - rc = pci_enable_device(pdev); - if (rc < 0) - return rc; - - rc = pci_request_regions(pdev, res_name); - if (rc < 0) - pci_disable_device(pdev); - - return rc; -} - -/* - * Release the regions and disable the PCI device. - * - * This must be matched with a previous successful call to comedi_pci_enable(). - */ -static inline void comedi_pci_disable(struct pci_dev *pdev) -{ - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -#endif diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index a804742b802..67a09aa6b72 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -21,12 +21,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ +*/ /* Driver: comedi_test Description: generates fake waveforms @@ -50,6 +45,7 @@ zero volts). */ +#include <linux/module.h> #include "../comedidev.h" #include <asm/div64.h> @@ -57,102 +53,109 @@ zero volts). #include "comedi_fc.h" #include <linux/timer.h> -/* Board descriptions */ -struct waveform_board { - const char *name; - int ai_chans; - int ai_bits; - int have_dio; -}; - #define N_CHANS 8 -static const struct waveform_board waveform_boards[] = { - { - .name = "comedi_test", - .ai_chans = N_CHANS, - .ai_bits = 16, - .have_dio = 0, - }, -}; - -#define thisboard ((const struct waveform_board *)dev->board_ptr) - /* Data unique to this driver */ struct waveform_private { struct timer_list timer; - struct timeval last; /* time at which last timer interrupt occurred */ + struct timeval last; /* time last timer interrupt occurred */ unsigned int uvolt_amplitude; /* waveform amplitude in microvolts */ unsigned long usec_period; /* waveform period in microseconds */ - unsigned long usec_current; /* current time (modulo waveform period) */ - unsigned long usec_remainder; /* usec since last scan; */ - unsigned long ai_count; /* number of conversions remaining */ + unsigned long usec_current; /* current time (mod waveform period) */ + unsigned long usec_remainder; /* usec since last scan */ + unsigned long ai_count; /* number of conversions remaining */ unsigned int scan_period; /* scan period in usec */ unsigned int convert_period; /* conversion period in usec */ - unsigned timer_running:1; unsigned int ao_loopbacks[N_CHANS]; }; -#define devpriv ((struct waveform_private *)dev->private) -static int waveform_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int waveform_detach(struct comedi_device *dev); -static struct comedi_driver driver_waveform = { - .driver_name = "comedi_test", - .module = THIS_MODULE, - .attach = waveform_attach, - .detach = waveform_detach, - .board_name = &waveform_boards[0].name, - .offset = sizeof(struct waveform_board), - .num_names = ARRAY_SIZE(waveform_boards), +/* 1000 nanosec in a microsec */ +static const int nano_per_micro = 1000; + +/* fake analog input ranges */ +static const struct comedi_lrange waveform_ai_ranges = { + 2, { + BIP_RANGE(10), + BIP_RANGE(5) + } }; -static int __init driver_waveform_init_module(void) +static unsigned short fake_sawtooth(struct comedi_device *dev, + unsigned int range_index, + unsigned long current_time) { - return comedi_driver_register(&driver_waveform); + struct waveform_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int offset = s->maxdata / 2; + u64 value; + const struct comedi_krange *krange = + &s->range_table->range[range_index]; + u64 binary_amplitude; + + binary_amplitude = s->maxdata; + binary_amplitude *= devpriv->uvolt_amplitude; + do_div(binary_amplitude, krange->max - krange->min); + + current_time %= devpriv->usec_period; + value = current_time; + value *= binary_amplitude * 2; + do_div(value, devpriv->usec_period); + value -= binary_amplitude; /* get rid of sawtooth's dc offset */ + + return offset + value; } -static void __exit driver_waveform_cleanup_module(void) +static unsigned short fake_squarewave(struct comedi_device *dev, + unsigned int range_index, + unsigned long current_time) { - comedi_driver_unregister(&driver_waveform); -} + struct waveform_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int offset = s->maxdata / 2; + u64 value; + const struct comedi_krange *krange = + &s->range_table->range[range_index]; + current_time %= devpriv->usec_period; -module_init(driver_waveform_init_module); -module_exit(driver_waveform_cleanup_module); + value = s->maxdata; + value *= devpriv->uvolt_amplitude; + do_div(value, krange->max - krange->min); -static int waveform_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int waveform_ai_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int waveform_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static int waveform_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int waveform_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static short fake_sawtooth(struct comedi_device *dev, unsigned int range, - unsigned long current_time); -static short fake_squarewave(struct comedi_device *dev, unsigned int range, - unsigned long current_time); -static short fake_flatline(struct comedi_device *dev, unsigned int range, - unsigned long current_time); -static short fake_waveform(struct comedi_device *dev, unsigned int channel, - unsigned int range, unsigned long current_time); + if (current_time < devpriv->usec_period / 2) + value *= -1; -/* 1000 nanosec in a microsec */ -static const int nano_per_micro = 1000; + return offset + value; +} -/* fake analog input ranges */ -static const struct comedi_lrange waveform_ai_ranges = { - 2, - { - BIP_RANGE(10), - BIP_RANGE(5), - } -}; +static unsigned short fake_flatline(struct comedi_device *dev, + unsigned int range_index, + unsigned long current_time) +{ + return dev->read_subdev->maxdata / 2; +} + +/* generates a different waveform depending on what channel is read */ +static unsigned short fake_waveform(struct comedi_device *dev, + unsigned int channel, unsigned int range, + unsigned long current_time) +{ + enum { + SAWTOOTH_CHAN, + SQUARE_CHAN, + }; + switch (channel) { + case SAWTOOTH_CHAN: + return fake_sawtooth(dev, range, current_time); + break; + case SQUARE_CHAN: + return fake_squarewave(dev, range, current_time); + break; + default: + break; + } + + return fake_flatline(dev, range, current_time); +} /* This is the background routine used to generate arbitrary data. @@ -162,6 +165,7 @@ static const struct comedi_lrange waveform_ai_ranges = { static void waveform_ai_interrupt(unsigned long arg) { struct comedi_device *dev = (struct comedi_device *)arg; + struct waveform_private *devpriv = dev->private; struct comedi_async *async = dev->read_subdev->async; struct comedi_cmd *cmd = &async->cmd; unsigned int i, j; @@ -169,6 +173,7 @@ static void waveform_ai_interrupt(unsigned long arg) unsigned long elapsed_time; unsigned int num_scans; struct timeval now; + bool stopping = false; do_gettimeofday(&now); @@ -180,219 +185,92 @@ static void waveform_ai_interrupt(unsigned long arg) (devpriv->usec_remainder + elapsed_time) / devpriv->scan_period; devpriv->usec_remainder = (devpriv->usec_remainder + elapsed_time) % devpriv->scan_period; - async->events = 0; + + if (cmd->stop_src == TRIG_COUNT) { + unsigned int remaining = cmd->stop_arg - devpriv->ai_count; + + if (num_scans >= remaining) { + /* about to finish */ + num_scans = remaining; + stopping = true; + } + } for (i = 0; i < num_scans; i++) { for (j = 0; j < cmd->chanlist_len; j++) { - cfc_write_to_buffer(dev->read_subdev, - fake_waveform(dev, - CR_CHAN(cmd-> - chanlist[j]), - CR_RANGE(cmd-> - chanlist[j]), - devpriv-> - usec_current + - i * - devpriv->scan_period + - j * - devpriv-> - convert_period)); - } - devpriv->ai_count++; - if (cmd->stop_src == TRIG_COUNT - && devpriv->ai_count >= cmd->stop_arg) { - async->events |= COMEDI_CB_EOA; - break; + unsigned short sample; + + sample = fake_waveform(dev, CR_CHAN(cmd->chanlist[j]), + CR_RANGE(cmd->chanlist[j]), + devpriv->usec_current + + i * devpriv->scan_period + + j * devpriv->convert_period); + cfc_write_to_buffer(dev->read_subdev, sample); } } + devpriv->ai_count += i; devpriv->usec_current += elapsed_time; devpriv->usec_current %= devpriv->usec_period; - if ((async->events & COMEDI_CB_EOA) == 0 && devpriv->timer_running) - mod_timer(&devpriv->timer, jiffies + 1); + if (stopping) + async->events |= COMEDI_CB_EOA; else - del_timer(&devpriv->timer); + mod_timer(&devpriv->timer, jiffies + 1); comedi_event(dev, dev->read_subdev); } -static int waveform_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int amplitude = it->options[0]; - int period = it->options[1]; - int i; - - dev->board_name = thisboard->name; - - if (alloc_private(dev, sizeof(struct waveform_private)) < 0) - return -ENOMEM; - - /* set default amplitude and period */ - if (amplitude <= 0) - amplitude = 1000000; /* 1 volt */ - if (period <= 0) - period = 100000; /* 0.1 sec */ - - devpriv->uvolt_amplitude = amplitude; - devpriv->usec_period = period; - - dev->n_subdevices = 2; - if (alloc_subdevices(dev, dev->n_subdevices) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - dev->read_subdev = s; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - s->n_chan = thisboard->ai_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = &waveform_ai_ranges; - s->len_chanlist = s->n_chan * 2; - s->insn_read = waveform_ai_insn_read; - s->do_cmd = waveform_ai_cmd; - s->do_cmdtest = waveform_ai_cmdtest; - s->cancel = waveform_ai_cancel; - - s = dev->subdevices + 1; - dev->write_subdev = s; - /* analog output subdevice (loopback) */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; - s->n_chan = thisboard->ai_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = &waveform_ai_ranges; - s->len_chanlist = s->n_chan * 2; - s->insn_write = waveform_ao_insn_write; - s->do_cmd = NULL; - s->do_cmdtest = NULL; - s->cancel = NULL; - - /* Our default loopback value is just a 0V flatline */ - for (i = 0; i < s->n_chan; i++) - devpriv->ao_loopbacks[i] = s->maxdata / 2; - - init_timer(&(devpriv->timer)); - devpriv->timer.function = waveform_ai_interrupt; - devpriv->timer.data = (unsigned long)dev; - - printk(KERN_INFO "comedi%d: comedi_test: " - "%i microvolt, %li microsecond waveform attached\n", dev->minor, - devpriv->uvolt_amplitude, devpriv->usec_period); - return 1; -} - -static int waveform_detach(struct comedi_device *dev) -{ - printk("comedi%d: comedi_test: remove\n", dev->minor); - - if (dev->private) - waveform_ai_cancel(dev, dev->read_subdev); - - return 0; -} - static int waveform_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + unsigned int arg; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW | TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW | TRIG_TIMER); + 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 2: make sure trigger sources are unique and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->convert_src != TRIG_NOW && cmd->convert_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + + if (cmd->convert_src == TRIG_NOW) + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->convert_src == TRIG_NOW) { - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - } if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < nano_per_micro) { - cmd->scan_begin_arg = nano_per_micro; - err++; - } - if (cmd->convert_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->chanlist_len) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->chanlist_len; - err++; - } - } - /* - * XXX these checks are generic and should go in core if not there - * already - */ - if (!cmd->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + nano_per_micro); + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + cmd->convert_arg * cmd->chanlist_len); } - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; @@ -400,22 +278,18 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; + arg = cmd->scan_begin_arg; /* round to nearest microsec */ - cmd->scan_begin_arg = - nano_per_micro * ((tmp + - (nano_per_micro / 2)) / nano_per_micro); - if (tmp != cmd->scan_begin_arg) - err++; + arg = nano_per_micro * + ((arg + (nano_per_micro / 2)) / nano_per_micro); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; + arg = cmd->convert_arg; /* round to nearest microsec */ - cmd->convert_arg = - nano_per_micro * ((tmp + - (nano_per_micro / 2)) / nano_per_micro); - if (tmp != cmd->convert_arg) - err++; + arg = nano_per_micro * + ((arg + (nano_per_micro / 2)) / nano_per_micro); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -427,6 +301,7 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, static int waveform_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct waveform_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; if (cmd->flags & TRIG_RT) { @@ -435,18 +310,13 @@ static int waveform_ai_cmd(struct comedi_device *dev, return -1; } - devpriv->timer_running = 1; devpriv->ai_count = 0; devpriv->scan_period = cmd->scan_begin_arg / nano_per_micro; if (cmd->convert_src == TRIG_NOW) devpriv->convert_period = 0; - else if (cmd->convert_src == TRIG_TIMER) + else /* TRIG_TIMER */ devpriv->convert_period = cmd->convert_arg / nano_per_micro; - else { - comedi_error(dev, "bug setting conversion period"); - return -1; - } do_gettimeofday(&devpriv->last); devpriv->usec_current = devpriv->last.tv_usec % devpriv->usec_period; @@ -460,87 +330,17 @@ static int waveform_ai_cmd(struct comedi_device *dev, static int waveform_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - devpriv->timer_running = 0; - del_timer(&devpriv->timer); - return 0; -} - -static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) -{ - struct comedi_subdevice *s = dev->read_subdev; - unsigned int offset = s->maxdata / 2; - u64 value; - const struct comedi_krange *krange = - &s->range_table->range[range_index]; - u64 binary_amplitude; - - binary_amplitude = s->maxdata; - binary_amplitude *= devpriv->uvolt_amplitude; - do_div(binary_amplitude, krange->max - krange->min); - - current_time %= devpriv->usec_period; - value = current_time; - value *= binary_amplitude * 2; - do_div(value, devpriv->usec_period); - value -= binary_amplitude; /* get rid of sawtooth's dc offset */ - - return offset + value; -} - -static short fake_squarewave(struct comedi_device *dev, - unsigned int range_index, - unsigned long current_time) -{ - struct comedi_subdevice *s = dev->read_subdev; - unsigned int offset = s->maxdata / 2; - u64 value; - const struct comedi_krange *krange = - &s->range_table->range[range_index]; - current_time %= devpriv->usec_period; - - value = s->maxdata; - value *= devpriv->uvolt_amplitude; - do_div(value, krange->max - krange->min); - - if (current_time < devpriv->usec_period / 2) - value *= -1; - - return offset + value; -} - -static short fake_flatline(struct comedi_device *dev, unsigned int range_index, - unsigned long current_time) -{ - return dev->read_subdev->maxdata / 2; -} - -/* generates a different waveform depending on what channel is read */ -static short fake_waveform(struct comedi_device *dev, unsigned int channel, - unsigned int range, unsigned long current_time) -{ - enum { - SAWTOOTH_CHAN, - SQUARE_CHAN, - }; - switch (channel) { - case SAWTOOTH_CHAN: - return fake_sawtooth(dev, range, current_time); - break; - case SQUARE_CHAN: - return fake_squarewave(dev, range, current_time); - break; - default: - break; - } + struct waveform_private *devpriv = dev->private; - return fake_flatline(dev, range, current_time); + del_timer_sync(&devpriv->timer); + return 0; } static int waveform_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct waveform_private *devpriv = dev->private; int i, chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) @@ -553,6 +353,7 @@ static int waveform_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct waveform_private *devpriv = dev->private; int i, chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) @@ -561,6 +362,89 @@ static int waveform_ao_insn_write(struct comedi_device *dev, return insn->n; } +static int waveform_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + struct waveform_private *devpriv; + struct comedi_subdevice *s; + int amplitude = it->options[0]; + int period = it->options[1]; + int i; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + /* set default amplitude and period */ + if (amplitude <= 0) + amplitude = 1000000; /* 1 volt */ + if (period <= 0) + period = 100000; /* 0.1 sec */ + + devpriv->uvolt_amplitude = amplitude; + devpriv->usec_period = period; + + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + + s = &dev->subdevices[0]; + dev->read_subdev = s; + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->n_chan = N_CHANS; + s->maxdata = 0xffff; + s->range_table = &waveform_ai_ranges; + s->len_chanlist = s->n_chan * 2; + s->insn_read = waveform_ai_insn_read; + s->do_cmd = waveform_ai_cmd; + s->do_cmdtest = waveform_ai_cmdtest; + s->cancel = waveform_ai_cancel; + + s = &dev->subdevices[1]; + dev->write_subdev = s; + /* analog output subdevice (loopback) */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; + s->n_chan = N_CHANS; + s->maxdata = 0xffff; + s->range_table = &waveform_ai_ranges; + s->insn_write = waveform_ao_insn_write; + + /* Our default loopback value is just a 0V flatline */ + for (i = 0; i < s->n_chan; i++) + devpriv->ao_loopbacks[i] = s->maxdata / 2; + + 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); + + return 0; +} + +static void waveform_detach(struct comedi_device *dev) +{ + struct waveform_private *devpriv = dev->private; + + if (devpriv) + waveform_ai_cancel(dev, dev->read_subdev); +} + +static struct comedi_driver waveform_driver = { + .driver_name = "comedi_test", + .module = THIS_MODULE, + .attach = waveform_attach, + .detach = waveform_detach, +}; +module_comedi_driver(waveform_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index 871f109bcfa..0a9c32e9db4 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -13,11 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: contec_pci_dio @@ -27,245 +22,106 @@ Author: Stefano Rivoir <s.rivoir@gts.it> Updated: Wed, 27 Jun 2007 13:00:06 +0100 Status: works -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration Options: not applicable, uses comedi PCI auto config */ -#include "../comedidev.h" +#include <linux/module.h> +#include <linux/pci.h> -#include "comedi_pci.h" - -enum contec_model { - PIO1616L = 0, -}; - -struct contec_board { - const char *name; - int model; - int in_ports; - int out_ports; - int in_offs; - int out_offs; - int out_boffs; -}; -static const struct contec_board contec_boards[] = { - {"PIO1616L", PIO1616L, 16, 16, 0, 2, 10}, -}; +#include "../comedidev.h" #define PCI_DEVICE_ID_PIO1616L 0x8172 -static DEFINE_PCI_DEVICE_TABLE(contec_pci_table) = { - { - PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, PIO1616L}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, contec_pci_table); - -#define thisboard ((const struct contec_board *)dev->board_ptr) - -struct contec_private { - int data; - - struct pci_dev *pci_dev; - -}; - -#define devpriv ((struct contec_private *)dev->private) - -static int contec_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int contec_detach(struct comedi_device *dev); -static struct comedi_driver driver_contec = { - .driver_name = "contec_pci_dio", - .module = THIS_MODULE, - .attach = contec_attach, - .detach = contec_detach, -}; - -/* Classic digital IO */ -static int contec_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int contec_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -#if 0 -static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -static int contec_ns_to_timer(unsigned int *ns, int round); -#endif - -static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - struct comedi_subdevice *s; - - printk("comedi%d: contec: ", dev->minor); - - dev->board_name = thisboard->name; - - if (alloc_private(dev, sizeof(struct contec_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_CONTEC && - pcidev->device == PCI_DEVICE_ID_PIO1616L) { - if (it->options[0] || it->options[1]) { - /* Check bus and slot. */ - if (it->options[0] != pcidev->bus->number || - it->options[1] != PCI_SLOT(pcidev->devfn)) { - continue; - } - } - devpriv->pci_dev = pcidev; - if (comedi_pci_enable(pcidev, "contec_pci_dio")) { - printk - ("error enabling PCI device and request regions!\n"); - return -EIO; - } - dev->iobase = pci_resource_start(pcidev, 0); - printk(" base addr %lx ", dev->iobase); - - dev->board_ptr = contec_boards + 0; - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = contec_di_insn_bits; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = contec_do_insn_bits; - - printk("attached\n"); - - return 1; - } - } - - printk("card not present!\n"); - - return -EIO; -} - -static int contec_detach(struct comedi_device *dev) -{ - printk("comedi%d: contec: remove\n", dev->minor); - - if (devpriv && devpriv->pci_dev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - - return 0; -} - -#if 0 -static int contec_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) -{ - printk("contec_cmdtest called\n"); - return 0; -} - -static int contec_ns_to_timer(unsigned int *ns, int round) -{ - return *ns; -} -#endif +/* + * Register map + */ +#define PIO1616L_DI_REG 0x00 +#define PIO1616L_DO_REG 0x02 static int contec_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + PIO1616L_DO_REG); - printk("contec_do_insn_bits called\n"); - printk(" data: %d %d\n", data[0], data[1]); + data[1] = s->state; - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - printk(" out: %d on %lx\n", s->state, - dev->iobase + thisboard->out_offs); - outw(s->state, dev->iobase + thisboard->out_offs); - } - return 2; + return insn->n; } static int contec_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + data[1] = inw(dev->iobase + PIO1616L_DI_REG); - printk("contec_di_insn_bits called\n"); - printk(" data: %d %d\n", data[0], data[1]); - - if (insn->n != 2) - return -EINVAL; - - data[1] = inw(dev->iobase + thisboard->in_offs); - - return 2; + return insn->n; } -static int __devinit driver_contec_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static int contec_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - return comedi_pci_auto_config(dev, driver_contec.driver_name); -} + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + int ret; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 0); + + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = contec_di_insn_bits; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = contec_do_insn_bits; -static void __devexit driver_contec_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); + return 0; } -static struct pci_driver driver_contec_pci_driver = { - .id_table = contec_pci_table, - .probe = &driver_contec_pci_probe, - .remove = __devexit_p(&driver_contec_pci_remove) +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, }; -static int __init driver_contec_init_module(void) +static int contec_pci_dio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_contec); - if (retval < 0) - return retval; - - driver_contec_pci_driver.name = (char *)driver_contec.driver_name; - return pci_register_driver(&driver_contec_pci_driver); + return comedi_pci_auto_config(dev, &contec_pci_dio_driver, + id->driver_data); } -static void __exit driver_contec_cleanup_module(void) -{ - pci_unregister_driver(&driver_contec_pci_driver); - comedi_driver_unregister(&driver_contec); -} +static const struct pci_device_id contec_pci_dio_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table); -module_init(driver_contec_init_module); -module_exit(driver_contec_cleanup_module); +static struct pci_driver contec_pci_dio_pci_driver = { + .name = "contec_pci_dio", + .id_table = contec_pci_dio_pci_table, + .probe = contec_pci_dio_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(contec_pci_dio_driver, contec_pci_dio_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c new file mode 100644 index 00000000000..df46e0a5bad --- /dev/null +++ b/drivers/staging/comedi/drivers/dac02.c @@ -0,0 +1,172 @@ +/* + * dac02.c + * Comedi driver for DAC02 compatible boards + * Copyright (C) 2014 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on the poc driver + * Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2001 David A. Schleef <ds@schleef.org> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +/* + * Driver: dac02 + * Description: Comedi driver for DAC02 compatible boards + * Devices: (Keithley Metrabyte) DAC-02 [dac02] + * Author: H Hartley Sweeten <hsweeten@visionengravers.com> + * Updated: Tue, 11 Mar 2014 11:27:19 -0700 + * Status: unknown + * + * Configuration options: + * [0] - I/O port base + */ + +#include <linux/module.h> + +#include "../comedidev.h" + +/* + * The output range is selected by jumpering pins on the I/O connector. + * + * Range Chan # Jumper pins Output + * ------------- ------ ------------- ----------------- + * 0 to 5V 0 21 to 22 24 + * 1 15 to 16 18 + * 0 to 10V 0 20 to 22 24 + * 1 14 to 16 18 + * +/-5V 0 21 to 22 23 + * 1 15 to 16 17 + * +/-10V 0 20 to 22 23 + * 1 14 to 16 17 + * 4 to 20mA 0 21 to 22 25 + * 1 15 to 16 19 + * AC reference 0 In on pin 22 24 (2-quadrant) + * In on pin 22 23 (4-quadrant) + * 1 In on pin 16 18 (2-quadrant) + * In on pin 16 17 (4-quadrant) + */ +static const struct comedi_lrange das02_ao_ranges = { + 6, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10), + RANGE_mA(4, 20), + RANGE_ext(0, 1) + } +}; + +struct dac02_private { + unsigned int ao_readback[2]; +}; + +/* + * Register I/O map + */ +#define DAC02_AO_LSB(x) (0x00 + ((x) * 2)) +#define DAC02_AO_MSB(x) (0x01 + ((x) * 2)) + +static int dac02_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dac02_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + devpriv->ao_readback[chan] = val; + + /* + * Unipolar outputs are true binary encoding. + * Bipolar outputs are complementary offset binary + * (that is, 0 = +full scale, maxdata = -full scale). + */ + if (comedi_range_is_bipolar(s, range)) + val = s->maxdata - val; + + /* + * DACs are double-buffered. + * Write LSB then MSB to latch output. + */ + outb((val << 4) & 0xf0, dev->iobase + DAC02_AO_LSB(chan)); + outb((val >> 4) & 0xff, dev->iobase + DAC02_AO_MSB(chan)); + } + + return insn->n; +} + +static int dac02_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dac02_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int dac02_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct dac02_private *devpriv; + struct comedi_subdevice *s; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], 0x08); + if (ret) + return ret; + + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + /* Analog Output subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &das02_ao_ranges; + s->insn_write = dac02_ao_insn_write; + s->insn_read = dac02_ao_insn_read; + + return 0; +} + +static struct comedi_driver dac02_driver = { + .driver_name = "dac02", + .module = THIS_MODULE, + .attach = dac02_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(dac02_driver); + +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_DESCRIPTION("Comedi driver for DAC02 compatible boards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index 82be77daa7d..a8f6036ad82 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: daqboard2000 @@ -31,16 +26,10 @@ Devices: [IOTech] DAQBoard/2000 (daqboard2000) Much of the functionality of this driver was determined from reading the source code for the Windows driver. -The FPGA on the board requires initialization code, which can -be loaded by comedi_config using the -i -option. The initialization code is available from http://www.comedi.org -in the comedi_nonfree_firmware tarball. +The FPGA on the board requires fimware, which is available from +http://www.comedi.org in the comedi_nonfree_firmware tarball. -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration options: not applicable, uses PCI auto config */ /* This card was obviously never intended to leave the Windows world, @@ -113,19 +102,19 @@ Configuration options: */ -#include "../comedidev.h" - +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> #include <linux/interrupt.h> -#include "comedi_pci.h" +#include "../comedidev.h" + #include "8255.h" -#define DAQBOARD2000_SUBSYSTEM_IDS2 0x00021616 /* Daqboard/2000 - 2 Dacs */ -#define DAQBOARD2000_SUBSYSTEM_IDS4 0x00041616 /* Daqboard/2000 - 4 Dacs */ +#define DAQBOARD2000_FIRMWARE "daqboard2000_firmware.bin" -#define DAQBOARD2000_DAQ_SIZE 0x1002 -#define DAQBOARD2000_PLX_SIZE 0x100 +#define DAQBOARD2000_SUBSYSTEM_IDS2 0x0002 /* Daqboard/2000 - 2 Dacs */ +#define DAQBOARD2000_SUBSYSTEM_IDS4 0x0004 /* Daqboard/2000 - 4 Dacs */ /* Initialization bits for the Serial EEPROM Control Register */ #define DAQBOARD2000_SECRProgPinHi 0x8001767e @@ -142,85 +131,56 @@ Configuration options: #define DAQBOARD2000_CPLD_INIT 0x0002 #define DAQBOARD2000_CPLD_DONE 0x0004 -/* Available ranges */ -static const struct comedi_lrange range_daqboard2000_ai = { 13, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, - 2.5), - RANGE(-1.25, - 1.25), - RANGE(-0.625, - 0.625), - RANGE(-0.3125, - 0.3125), - RANGE(-0.156, - 0.156), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25), - RANGE(0, - 0.625), - RANGE(0, - 0.3125) - } -}; - -static const struct comedi_lrange range_daqboard2000_ao = { 1, { - RANGE(-10, 10) - } +static const struct comedi_lrange range_daqboard2000_ai = { + 13, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125), + BIP_RANGE(0.156), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + UNI_RANGE(0.625), + UNI_RANGE(0.3125) + } }; -struct daqboard2000_hw { - volatile u16 acqControl; /* 0x00 */ - volatile u16 acqScanListFIFO; /* 0x02 */ - volatile u32 acqPacerClockDivLow; /* 0x04 */ - - volatile u16 acqScanCounter; /* 0x08 */ - volatile u16 acqPacerClockDivHigh; /* 0x0a */ - volatile u16 acqTriggerCount; /* 0x0c */ - volatile u16 fill2; /* 0x0e */ - volatile u16 acqResultsFIFO; /* 0x10 */ - volatile u16 fill3; /* 0x12 */ - volatile u16 acqResultsShadow; /* 0x14 */ - volatile u16 fill4; /* 0x16 */ - volatile u16 acqAdcResult; /* 0x18 */ - volatile u16 fill5; /* 0x1a */ - volatile u16 dacScanCounter; /* 0x1c */ - volatile u16 fill6; /* 0x1e */ - - volatile u16 dacControl; /* 0x20 */ - volatile u16 fill7; /* 0x22 */ - volatile s16 dacFIFO; /* 0x24 */ - volatile u16 fill8[2]; /* 0x26 */ - volatile u16 dacPacerClockDiv; /* 0x2a */ - volatile u16 refDacs; /* 0x2c */ - volatile u16 fill9; /* 0x2e */ - - volatile u16 dioControl; /* 0x30 */ - volatile s16 dioP3hsioData; /* 0x32 */ - volatile u16 dioP3Control; /* 0x34 */ - volatile u16 calEepromControl; /* 0x36 */ - volatile s16 dacSetting[4]; /* 0x38 */ - volatile s16 dioP2ExpansionIO8Bit[32]; /* 0x40 */ - - volatile u16 ctrTmrControl; /* 0x80 */ - volatile u16 fill10[3]; /* 0x82 */ - volatile s16 ctrInput[4]; /* 0x88 */ - volatile u16 fill11[8]; /* 0x90 */ - volatile u16 timerDivisor[2]; /* 0xa0 */ - volatile u16 fill12[6]; /* 0xa4 */ - - volatile u16 dmaControl; /* 0xb0 */ - volatile u16 trigControl; /* 0xb2 */ - volatile u16 fill13[2]; /* 0xb4 */ - volatile u16 calEeprom; /* 0xb8 */ - volatile u16 acqDigitalMark; /* 0xba */ - volatile u16 trigDacs; /* 0xbc */ - volatile u16 fill14; /* 0xbe */ - volatile s16 dioP2ExpansionIO16Bit[32]; /* 0xc0 */ -}; +/* + * Register Memory Map + */ +#define acqControl 0x00 /* u16 */ +#define acqScanListFIFO 0x02 /* u16 */ +#define acqPacerClockDivLow 0x04 /* u32 */ +#define acqScanCounter 0x08 /* u16 */ +#define acqPacerClockDivHigh 0x0a /* u16 */ +#define acqTriggerCount 0x0c /* u16 */ +#define acqResultsFIFO 0x10 /* u16 */ +#define acqResultsShadow 0x14 /* u16 */ +#define acqAdcResult 0x18 /* u16 */ +#define dacScanCounter 0x1c /* u16 */ +#define dacControl 0x20 /* u16 */ +#define dacFIFO 0x24 /* s16 */ +#define dacPacerClockDiv 0x2a /* u16 */ +#define refDacs 0x2c /* u16 */ +#define dioControl 0x30 /* u16 */ +#define dioP3hsioData 0x32 /* s16 */ +#define dioP3Control 0x34 /* u16 */ +#define calEepromControl 0x36 /* u16 */ +#define dacSetting(x) (0x38 + (x)*2) /* s16 */ +#define dioP2ExpansionIO8Bit 0x40 /* s16 */ +#define ctrTmrControl 0x80 /* u16 */ +#define ctrInput(x) (0x88 + (x)*2) /* s16 */ +#define timerDivisor(x) (0xa0 + (x)*2) /* u16 */ +#define dmaControl 0xb0 /* u16 */ +#define trigControl 0xb2 /* u16 */ +#define calEeprom 0xb8 /* u16 */ +#define acqDigitalMark 0xba /* u16 */ +#define trigDacs 0xbc /* u16 */ +#define dioP2ExpansionIO16Bit(x) (0xc0 + (x)*2) /* s16 */ /* Scan Sequencer programming */ #define DAQBOARD2000_SeqStartScanList 0x0011 @@ -301,17 +261,6 @@ struct daqboard2000_hw { #define DAQBOARD2000_PosRefDacSelect 0x0100 #define DAQBOARD2000_NegRefDacSelect 0x0000 -static int daqboard2000_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int daqboard2000_detach(struct comedi_device *dev); - -static struct comedi_driver driver_daqboard2000 = { - .driver_name = "daqboard2000", - .module = THIS_MODULE, - .attach = daqboard2000_attach, - .detach = daqboard2000_detach, -}; - struct daq200_boardtype { const char *name; int id; @@ -321,38 +270,23 @@ static const struct daq200_boardtype boardtypes[] = { {"ids4", DAQBOARD2000_SUBSYSTEM_IDS4}, }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct daq200_boardtype)) -#define this_board ((const struct daq200_boardtype *)dev->board_ptr) - -static DEFINE_PCI_DEVICE_TABLE(daqboard2000_pci_table) = { - { - 0x1616, 0x0409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table); - struct daqboard2000_private { enum { card_daqboard_2000 } card; - struct pci_dev *pci_dev; - void *daq; - void *plx; - int got_regions; + void __iomem *daq; + void __iomem *plx; unsigned int ao_readback[2]; }; -#define devpriv ((struct daqboard2000_private *)dev->private) - static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry) { - struct daqboard2000_hw *fpga = devpriv->daq; + struct daqboard2000_private *devpriv = dev->private; -/* udelay(4); */ - fpga->acqScanListFIFO = entry & 0x00ff; -/* udelay(4); */ - fpga->acqScanListFIFO = (entry >> 8) & 0x00ff; + /* udelay(4); */ + writew(entry & 0x00ff, devpriv->daq + acqScanListFIFO); + /* udelay(4); */ + writew((entry >> 8) & 0x00ff, devpriv->daq + acqScanListFIFO); } static void setup_sampling(struct comedi_device *dev, int chan, int gain) @@ -393,30 +327,47 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain) /* These should be read from EEPROM */ word2 |= 0x0800; word3 |= 0xc000; -/* printk("%d %4.4x %4.4x %4.4x %4.4x\n", chan, word0, word1, word2, word3);*/ writeAcqScanListEntry(dev, word0); writeAcqScanListEntry(dev, word1); writeAcqScanListEntry(dev, word2); writeAcqScanListEntry(dev, word3); } +static int daqboard2000_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->daq + acqControl); + if (status & context) + return 0; + return -EBUSY; +} + static int daqboard2000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct daqboard2000_private *devpriv = dev->private; + int gain, chan; + int ret; int i; - struct daqboard2000_hw *fpga = devpriv->daq; - int gain, chan, timeout; - fpga->acqControl = - DAQBOARD2000_AcqResetScanListFifo | - DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe; + writew(DAQBOARD2000_AcqResetScanListFifo | + DAQBOARD2000_AcqResetResultsFifo | + DAQBOARD2000_AcqResetConfigPipe, devpriv->daq + acqControl); - /* If pacer clock is not set to some high value (> 10 us), we - risk multiple samples to be put into the result FIFO. */ - fpga->acqPacerClockDivLow = 1000000; /* 1 second, should be long enough */ - fpga->acqPacerClockDivHigh = 0; + /* + * If pacer clock is not set to some high value (> 10 us), we + * risk multiple samples to be put into the result FIFO. + */ + /* 1 second, should be long enough */ + writel(1000000, devpriv->daq + acqPacerClockDivLow); + writew(0, devpriv->daq + acqPacerClockDivHigh); gain = CR_RANGE(insn->chanspec); chan = CR_CHAN(insn->chanspec); @@ -428,30 +379,29 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { setup_sampling(dev, chan, gain); /* Enable reading from the scanlist FIFO */ - fpga->acqControl = DAQBOARD2000_SeqStartScanList; - for (timeout = 0; timeout < 20; timeout++) { - if (fpga->acqControl & DAQBOARD2000_AcqConfigPipeFull) { - break; - } - /* udelay(2); */ - } - fpga->acqControl = DAQBOARD2000_AdcPacerEnable; - for (timeout = 0; timeout < 20; timeout++) { - if (fpga->acqControl & DAQBOARD2000_AcqLogicScanning) { - break; - } - /* udelay(2); */ - } - for (timeout = 0; timeout < 20; timeout++) { - if (fpga->acqControl & - DAQBOARD2000_AcqResultsFIFOHasValidData) { - break; - } - /* udelay(2); */ - } - data[i] = fpga->acqResultsFIFO; - fpga->acqControl = DAQBOARD2000_AdcPacerDisable; - fpga->acqControl = DAQBOARD2000_SeqStopScanList; + writew(DAQBOARD2000_SeqStartScanList, + devpriv->daq + acqControl); + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqConfigPipeFull); + if (ret) + return ret; + + writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl); + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqLogicScanning); + if (ret) + return ret; + + ret = comedi_timeout(dev, s, insn, daqboard2000_ai_status, + DAQBOARD2000_AcqResultsFIFOHasValidData); + if (ret) + return ret; + + data[i] = readw(devpriv->daq + acqResultsFIFO); + writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl); + writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl); } return i; @@ -462,44 +412,67 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int i; + struct daqboard2000_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); + int i; - for (i = 0; i < insn->n; 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, + unsigned long context) +{ + struct daqboard2000_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int status; + + status = readw(devpriv->daq + dacControl); + if ((status & ((chan + 1) * 0x0010)) == 0) + return 0; + return -EBUSY; +} + static int daqboard2000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i; + struct daqboard2000_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); - struct daqboard2000_hw *fpga = devpriv->daq; - int timeout; + int ret; + 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... + * OK, since it works OK without enabling the DAC's, + * let's keep it as simple as possible... */ - /* fpga->dacControl = (chan + 2) * 0x0010 | 0x0001; udelay(1000); */ - fpga->dacSetting[chan] = data[i]; - for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & ((chan + 1) * 0x0010)) == 0) { - break; - } - /* udelay(2); */ - } + writew((chan + 2) * 0x0010 | 0x0001, + devpriv->daq + dacControl); + udelay(1000); +#endif + writew(data[i], devpriv->daq + 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... - * fpga->dacControl = (chan + 2) * 0x0010 | 0x0000; udelay(1000); + * Since we never enabled the DAC's, we don't need + * to disable it... */ + writew((chan + 2) * 0x0010 | 0x0000, + devpriv->daq + dacControl); + udelay(1000); +#endif } return i; @@ -507,35 +480,39 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, static void daqboard2000_resetLocalBus(struct comedi_device *dev) { - printk("daqboard2000_resetLocalBus\n"); + struct daqboard2000_private *devpriv = dev->private; + writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c); - udelay(10000); + mdelay(10); writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c); - udelay(10000); + mdelay(10); } static void daqboard2000_reloadPLX(struct comedi_device *dev) { - printk("daqboard2000_reloadPLX\n"); + struct daqboard2000_private *devpriv = dev->private; + writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c); - udelay(10000); + mdelay(10); writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c); - udelay(10000); + mdelay(10); writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c); - udelay(10000); + mdelay(10); } static void daqboard2000_pulseProgPin(struct comedi_device *dev) { - printk("daqboard2000_pulseProgPin 1\n"); + struct daqboard2000_private *devpriv = dev->private; + writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c); - udelay(10000); + mdelay(10); writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c); - udelay(10000); /* Not in the original code, but I like symmetry... */ + mdelay(10); /* Not in the original code, but I like symmetry... */ } static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask) { + struct daqboard2000_private *devpriv = dev->private; int result = 0; int i; int cpld; @@ -555,6 +532,7 @@ static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask) static int daqboard2000_writeCPLD(struct comedi_device *dev, int data) { + struct daqboard2000_private *devpriv = dev->private; int result = 0; udelay(10); @@ -567,52 +545,38 @@ static int daqboard2000_writeCPLD(struct comedi_device *dev, int data) } static int initialize_daqboard2000(struct comedi_device *dev, - unsigned char *cpld_array, int len) + const u8 *cpld_array, size_t len, + unsigned long context) { + struct daqboard2000_private *devpriv = dev->private; int result = -EIO; /* Read the serial EEPROM control register */ int secr; int retry; - int i; + size_t i; /* Check to make sure the serial eeprom is present on the board */ secr = readl(devpriv->plx + 0x6c); - if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) { -#ifdef DEBUG_EEPROM - printk("no serial eeprom\n"); -#endif + if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) return -EIO; - } for (retry = 0; retry < 3; retry++) { -#ifdef DEBUG_EEPROM - printk("Programming EEPROM try %x\n", retry); -#endif - daqboard2000_resetLocalBus(dev); daqboard2000_reloadPLX(dev); daqboard2000_pulseProgPin(dev); if (daqboard2000_pollCPLD(dev, DAQBOARD2000_CPLD_INIT)) { for (i = 0; i < len; i++) { - if (cpld_array[i] == 0xff - && cpld_array[i + 1] == 0x20) { -#ifdef DEBUG_EEPROM - printk("Preamble found at %d\n", i); -#endif + if (cpld_array[i] == 0xff && + cpld_array[i + 1] == 0x20) break; - } } for (; i < len; i += 2) { int data = (cpld_array[i] << 8) + cpld_array[i + 1]; - if (!daqboard2000_writeCPLD(dev, data)) { + if (!daqboard2000_writeCPLD(dev, data)) break; - } } if (i >= len) { -#ifdef DEBUG_EEPROM - printk("Programmed\n"); -#endif daqboard2000_resetLocalBus(dev); daqboard2000_reloadPLX(dev); result = 0; @@ -625,26 +589,27 @@ static int initialize_daqboard2000(struct comedi_device *dev, static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev) { -/* printk("Implement: daqboard2000_adcStopDmaTransfer\n");*/ } static void daqboard2000_adcDisarm(struct comedi_device *dev) { - struct daqboard2000_hw *fpga = devpriv->daq; + struct daqboard2000_private *devpriv = dev->private; /* Disable hardware triggers */ udelay(2); - fpga->trigControl = DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable; + writew(DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable, + devpriv->daq + trigControl); udelay(2); - fpga->trigControl = DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable; + writew(DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable, + devpriv->daq + trigControl); /* Stop the scan list FIFO from loading the configuration pipe */ udelay(2); - fpga->acqControl = DAQBOARD2000_SeqStopScanList; + writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl); /* Stop the pacer clock */ udelay(2); - fpga->acqControl = DAQBOARD2000_AdcPacerDisable; + writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl); /* Stop the input dma (abort channel 1) */ daqboard2000_adcStopDmaTransfer(dev); @@ -652,43 +617,39 @@ static void daqboard2000_adcDisarm(struct comedi_device *dev) static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) { - struct daqboard2000_hw *fpga = devpriv->daq; + struct daqboard2000_private *devpriv = dev->private; + unsigned int val; int timeout; /* Set the + reference dac value in the FPGA */ - fpga->refDacs = 0x80 | DAQBOARD2000_PosRefDacSelect; + writew(0x80 | DAQBOARD2000_PosRefDacSelect, devpriv->daq + refDacs); for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) { + val = readw(devpriv->daq + dacControl); + if ((val & DAQBOARD2000_RefBusy) == 0) break; - } udelay(2); } -/* printk("DAQBOARD2000_PosRefDacSelect %d\n", timeout);*/ /* Set the - reference dac value in the FPGA */ - fpga->refDacs = 0x80 | DAQBOARD2000_NegRefDacSelect; + writew(0x80 | DAQBOARD2000_NegRefDacSelect, devpriv->daq + refDacs); for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) { + val = readw(devpriv->daq + dacControl); + if ((val & DAQBOARD2000_RefBusy) == 0) break; - } udelay(2); } -/* printk("DAQBOARD2000_NegRefDacSelect %d\n", timeout);*/ } static void daqboard2000_initializeCtrs(struct comedi_device *dev) { -/* printk("Implement: daqboard2000_initializeCtrs\n");*/ } static void daqboard2000_initializeTmrs(struct comedi_device *dev) { -/* printk("Implement: daqboard2000_initializeTmrs\n");*/ } static void daqboard2000_dacDisarm(struct comedi_device *dev) { -/* printk("Implement: daqboard2000_dacDisarm\n");*/ } static void daqboard2000_initializeAdc(struct comedi_device *dev) @@ -704,137 +665,80 @@ static void daqboard2000_initializeDac(struct comedi_device *dev) daqboard2000_dacDisarm(dev); } -/* -The test command, REMOVE!!: - -rmmod daqboard2000 ; rmmod comedi; make install ; modprobe daqboard2000; /usr/sbin/comedi_config /dev/comedi0 daqboard/2000 ; tail -40 /var/log/messages -*/ - static int daqboard2000_8255_cb(int dir, int port, int data, unsigned long ioaddr) { - int result = 0; + void __iomem *mmio_base = (void __iomem *)ioaddr; + if (dir) { - writew(data, ((void *)ioaddr) + port * 2); - result = 0; + writew(data, mmio_base + port * 2); + return 0; } else { - result = readw(((void *)ioaddr) + port * 2); + return readw(mmio_base + port * 2); } -/* - printk("daqboard2000_8255_cb %x %d %d %2.2x -> %2.2x\n", - arg, dir, port, data, result); -*/ - return result; } -static int daqboard2000_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static const void *daqboard2000_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { - int result = 0; - struct comedi_subdevice *s; - struct pci_dev *card = NULL; - void *aux_data; - unsigned int aux_len; - int bus, slot; - - printk("comedi%d: daqboard2000:", dev->minor); + const struct daq200_boardtype *board; + int i; - bus = it->options[0]; - slot = it->options[1]; + if (pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH) + return NULL; - result = alloc_private(dev, sizeof(struct daqboard2000_private)); - if (result < 0) { - return -ENOMEM; - } - for (card = pci_get_device(0x1616, 0x0409, NULL); - card != NULL; card = pci_get_device(0x1616, 0x0409, card)) { - if (bus || slot) { - /* requested particular bus/slot */ - if (card->bus->number != bus || - PCI_SLOT(card->devfn) != slot) { - continue; - } - } - break; /* found one */ - } - if (!card) { - if (bus || slot) - printk(" no daqboard2000 found at bus/slot: %d/%d\n", - bus, slot); - else - printk(" no daqboard2000 found\n"); - return -EIO; - } else { - u32 id; - int i; - devpriv->pci_dev = card; - id = ((u32) card-> - subsystem_device << 16) | card->subsystem_vendor; - for (i = 0; i < n_boardtypes; i++) { - if (boardtypes[i].id == id) { - printk(" %s", boardtypes[i].name); - dev->board_ptr = boardtypes + i; - } - } - if (!dev->board_ptr) { - printk - (" unknown subsystem id %08x (pretend it is an ids2)", - id); - dev->board_ptr = boardtypes; - } + for (i = 0; i < ARRAY_SIZE(boardtypes); i++) { + board = &boardtypes[i]; + if (pcidev->subsystem_device == board->id) + return board; } + return NULL; +} - result = comedi_pci_enable(card, "daqboard2000"); - if (result < 0) { - printk(" failed to enable PCI device and request regions\n"); - return -EIO; - } - devpriv->got_regions = 1; - devpriv->plx = - ioremap(pci_resource_start(card, 0), DAQBOARD2000_PLX_SIZE); - devpriv->daq = - ioremap(pci_resource_start(card, 2), DAQBOARD2000_DAQ_SIZE); - if (!devpriv->plx || !devpriv->daq) { +static int daqboard2000_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct daq200_boardtype *board; + struct daqboard2000_private *devpriv; + struct comedi_subdevice *s; + int result; + + board = daqboard2000_find_boardinfo(dev, pcidev); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - } - result = alloc_subdevices(dev, 3); - if (result < 0) - goto out; + result = comedi_pci_enable(dev); + if (result) + return result; - readl(devpriv->plx + 0x6c); + devpriv->plx = pci_ioremap_bar(pcidev, 0); + devpriv->daq = pci_ioremap_bar(pcidev, 2); + if (!devpriv->plx || !devpriv->daq) + return -ENOMEM; - /* - u8 interrupt; - Windows code does restore interrupts, but since we don't use them... - pci_read_config_byte(card, PCI_INTERRUPT_LINE, &interrupt); - printk("Interrupt before is: %x\n", interrupt); - */ + result = comedi_alloc_subdevices(dev, 3); + if (result) + return result; - aux_data = comedi_aux_data(it->options, 0); - aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; + readl(devpriv->plx + 0x6c); - if (aux_data && aux_len) { - result = initialize_daqboard2000(dev, aux_data, aux_len); - } else { - printk("no FPGA initialization code, aborting\n"); - result = -EIO; - } + result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + DAQBOARD2000_FIRMWARE, + initialize_daqboard2000, 0); if (result < 0) - goto out; + return result; + daqboard2000_initializeAdc(dev); daqboard2000_initializeDac(dev); - /* - Windows code does restore interrupts, but since we don't use them... - pci_read_config_byte(card, PCI_INTERRUPT_LINE, &interrupt); - printk("Interrupt after is: %x\n", interrupt); - */ - - dev->iobase = (unsigned long)devpriv->daq; - - dev->board_name = this_board->name; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -843,7 +747,7 @@ static int daqboard2000_attach(struct comedi_device *dev, s->insn_read = daqboard2000_ai_insn_read; s->range_table = &range_daqboard2000_ai; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -851,82 +755,61 @@ static int daqboard2000_attach(struct comedi_device *dev, s->maxdata = 0xffff; s->insn_read = daqboard2000_ao_insn_read; s->insn_write = daqboard2000_ao_insn_write; - s->range_table = &range_daqboard2000_ao; + s->range_table = &range_bipolar10; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; result = subdev_8255_init(dev, s, daqboard2000_8255_cb, - (unsigned long)(dev->iobase + 0x40)); + (unsigned long)(devpriv->daq + dioP2ExpansionIO8Bit)); + if (result) + return result; - printk("\n"); -out: - return result; + return 0; } -static int daqboard2000_detach(struct comedi_device *dev) +static void daqboard2000_detach(struct comedi_device *dev) { - printk("comedi%d: daqboard2000: remove\n", dev->minor); + struct daqboard2000_private *devpriv = dev->private; - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 2); - - if (dev->irq) { + if (dev->irq) free_irq(dev->irq, dev); - } if (devpriv) { if (devpriv->daq) iounmap(devpriv->daq); if (devpriv->plx) iounmap(devpriv->plx); - if (devpriv->pci_dev) { - if (devpriv->got_regions) { - comedi_pci_disable(devpriv->pci_dev); - } - pci_dev_put(devpriv->pci_dev); - } } - return 0; -} - -static int __devinit driver_daqboard2000_pci_probe(struct pci_dev *dev, - const struct pci_device_id - *ent) -{ - return comedi_pci_auto_config(dev, driver_daqboard2000.driver_name); -} - -static void __devexit driver_daqboard2000_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); + comedi_pci_disable(dev); } -static struct pci_driver driver_daqboard2000_pci_driver = { - .id_table = daqboard2000_pci_table, - .probe = &driver_daqboard2000_pci_probe, - .remove = __devexit_p(&driver_daqboard2000_pci_remove) +static struct comedi_driver daqboard2000_driver = { + .driver_name = "daqboard2000", + .module = THIS_MODULE, + .auto_attach = daqboard2000_auto_attach, + .detach = daqboard2000_detach, }; -static int __init driver_daqboard2000_init_module(void) +static int daqboard2000_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_daqboard2000); - if (retval < 0) - return retval; - - driver_daqboard2000_pci_driver.name = - (char *)driver_daqboard2000.driver_name; - return pci_register_driver(&driver_daqboard2000_pci_driver); + return comedi_pci_auto_config(dev, &daqboard2000_driver, + id->driver_data); } -static void __exit driver_daqboard2000_cleanup_module(void) -{ - pci_unregister_driver(&driver_daqboard2000_pci_driver); - comedi_driver_unregister(&driver_daqboard2000); -} +static const struct pci_device_id daqboard2000_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_IOTECH, 0x0409) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, daqboard2000_pci_table); -module_init(driver_daqboard2000_init_module); -module_exit(driver_daqboard2000_cleanup_module); +static struct pci_driver daqboard2000_pci_driver = { + .name = "daqboard2000", + .id_table = daqboard2000_pci_table, + .probe = daqboard2000_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(DAQBOARD2000_FIRMWARE); diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index 3141dc80fe7..c5e352fb555 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -1,6 +1,6 @@ /* * comedi/drivers/das08.c - * DAS08 driver + * comedi driver for common DAS08 support (used by ISA/PCI/PCMCIA drivers) * * COMEDI - Linux Control and Measurement Device Interface * Copyright (C) 2000 David A. Schleef <ds@schleef.org> @@ -16,65 +16,31 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - ***************************************************************** */ /* * Driver: das08 * Description: DAS-08 compatible boards + * Devices: various, see das08_isa, das08_cs, and das08_pci drivers * Author: Warren Jasper, ds, Frank Hess - * Devices: [Keithley Metrabyte] DAS08 (isa-das08), - * [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm), - * DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh), - * DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao), - * DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (das08), - * PC104-DAS08 (pc104-das08), DAS08/JR/16 (das08jr/16) + * Updated: Fri, 31 Aug 2012 19:19:06 +0100 * Status: works * - * This is a rewrite of the das08 and das08jr drivers. - * - * Options (for ISA cards): - * [0] - base io address + * This driver is used by the das08_isa, das08_cs, and das08_pci + * drivers to provide the common support for the DAS-08 hardware. * - * Options (for pci-das08): - * [0] - bus (optional) - * [1] = slot (optional) - * - * The das08 driver doesn't support asynchronous commands, since - * the cheap das08 hardware doesn't really support them. The - * comedi_rt_timer driver can be used to emulate commands for this - * driver. + * The driver doesn't support asynchronous commands, since the + * cheap das08 hardware doesn't really support them. */ -#include "../comedidev.h" +#include <linux/module.h> -#include <linux/delay.h> +#include "../comedidev.h" -#include "comedi_pci.h" #include "8255.h" +#include "8253.h" #include "das08.h" -#define DRV_NAME "das08" - -#define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307 -#define PCI_DEVICE_ID_PCIDAS08 0x29 -#define PCIDAS08_SIZE 0x54 - -/* pci configuration registers */ -#define INTCSR 0x4c -#define INTR1_ENABLE 0x1 -#define INTR1_HIGH_POLARITY 0x2 -#define PCI_INTR_ENABLE 0x40 -#define INTR1_EDGE_TRIG 0x100 /* requires high polarity */ -#define CNTRL 0x50 -#define CNTRL_DIR 0x2 -#define CNTRL_INTR 0x4 - /* cio-das08.pdf @@ -154,67 +120,49 @@ /* gainlist same as _pgx_ below */ -static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das08jr_di_rbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das08jr_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das08jr_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das08ao_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static void i8254_set_mode_low(unsigned int base, int channel, - unsigned int mode); - -static const struct comedi_lrange range_das08_pgl = { 9, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } +static const struct comedi_lrange range_das08_pgl = { + 9, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_das08_pgh = { 12, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(1), - BIP_RANGE(0.5), - BIP_RANGE(0.1), - BIP_RANGE(0.05), - BIP_RANGE(0.01), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - } +static const struct comedi_lrange range_das08_pgh = { + 12, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.1), + BIP_RANGE(0.05), + BIP_RANGE(0.01), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; -static const struct comedi_lrange range_das08_pgm = { 9, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.01), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01) - } +static const struct comedi_lrange range_das08_pgm = { + 9, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.01), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; /* cio-das08jr.pdf @@ -253,280 +201,29 @@ static const int *const das08_gainlists[] = { das08_pgm_gainlist, }; -static const struct das08_board_struct das08_boards[] = { - { - .name = "isa-das08", /* cio-das08.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode12, - .ao = NULL, - .ao_nbits = 12, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 8, - .i8254_offset = 4, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-pgm", /* cio-das08pgx.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pgm, - .ai_encoding = das08_encode12, - .ao = NULL, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-pgh", /* cio-das08pgx.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pgh, - .ai_encoding = das08_encode12, - .ao = NULL, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-pgl", /* cio-das08pgx.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pgl, - .ai_encoding = das08_encode12, - .ao = NULL, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-aoh", /* cio-das08_aox.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pgh, - .ai_encoding = das08_encode12, - .ao = das08ao_ao_winsn, /* 8 */ - .ao_nbits = 12, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0x0c, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-aol", /* cio-das08_aox.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pgl, - .ai_encoding = das08_encode12, - .ao = das08ao_ao_winsn, /* 8 */ - .ao_nbits = 12, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0x0c, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08-aom", /* cio-das08_aox.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pgm, - .ai_encoding = das08_encode12, - .ao = das08ao_ao_winsn, /* 8 */ - .ao_nbits = 12, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0x0c, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08/jr-ao", /* cio-das08-jr-ao.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode12, - .ao = das08jr_ao_winsn, - .ao_nbits = 12, - .di = das08jr_di_rbits, - .do_ = das08jr_do_wbits, - .do_nchan = 8, - .i8255_offset = 0, - .i8254_offset = 0, - .iosize = 16, /* unchecked */ - }, - { - .name = "das08jr-16-ao", /* cio-das08jr-16-ao.pdf */ - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 16, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode12, - .ao = das08jr_ao_winsn, - .ao_nbits = 16, - .di = das08jr_di_rbits, - .do_ = das08jr_do_wbits, - .do_nchan = 8, - .i8255_offset = 0, - .i8254_offset = 0x04, - .iosize = 16, /* unchecked */ - }, -#ifdef CONFIG_COMEDI_PCI - { - .name = "das08", /* pci-das08 */ - .id = PCI_DEVICE_ID_PCIDAS08, - .bustype = pci, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0, - .i8254_offset = 4, - .iosize = 8, - }, -#endif - { - .name = "pc104-das08", - .bustype = pc104, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 4, - .i8255_offset = 0, - .i8254_offset = 4, - .iosize = 16, /* unchecked */ - }, -#if 0 - { - .name = "das08/f", - }, - { - .name = "das08jr", - }, -#endif - { - .name = "das08jr/16", - .bustype = isa, - .ai = das08_ai_rinsn, - .ai_nbits = 16, - .ai_pg = das08_pg_none, - .ai_encoding = das08_encode16, - .ao = NULL, - .ao_nbits = 0, - .di = das08jr_di_rbits, - .do_ = das08jr_do_wbits, - .do_nchan = 8, - .i8255_offset = 0, - .i8254_offset = 0, - .iosize = 16, /* unchecked */ - }, -#if 0 - { - .name = "das48-pga", /* cio-das48-pga.pdf */ - }, - { - .name = "das08-pga-g2", /* a KM board */ - }, -#endif -}; - -#ifdef CONFIG_COMEDI_PCMCIA -struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = { - { - .name = "pcm-das08", - .id = 0x0, /* XXX */ - .bustype = pcmcia, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_pcm_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 3, - .i8255_offset = 0, - .i8254_offset = 0, - .iosize = 16, - }, - /* duplicate so driver name can be used also */ - { - .name = "das08_cs", - .id = 0x0, /* XXX */ - .bustype = pcmcia, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_pcm_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 3, - .i8255_offset = 0, - .i8254_offset = 0, - .iosize = 16, - }, -}; -#endif - -#ifdef CONFIG_COMEDI_PCI -static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = { - { - PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, das08_pci_table); -#endif - -#define devpriv ((struct das08_private_struct *)dev->private) -#define thisboard ((const struct das08_board_struct *)dev->board_ptr) +static int das08_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; -#define TIMEOUT 100000 + status = inb(dev->iobase + DAS08_STATUS); + if ((status & DAS08_EOC) == 0) + return 0; + return -EBUSY; +} static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i, n; + const struct das08_board_struct *thisboard = comedi_board(dev); + struct das08_private_struct *devpriv = dev->private; + int n; int chan; int range; int lsb, msb; + int ret; chan = CR_CHAN(insn->chanspec); range = CR_RANGE(insn->chanspec); @@ -554,19 +251,15 @@ static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* clear over-range bits for 16-bit boards */ if (thisboard->ai_nbits == 16) if (inb(dev->iobase + DAS08_MSB) & 0x80) - printk(KERN_INFO "das08: over-range\n"); + dev_info(dev->class_dev, "over-range\n"); /* trigger conversion */ outb_p(0, dev->iobase + DAS08_TRIG_12BIT); - for (i = 0; i < TIMEOUT; i++) { - if (!(inb(dev->iobase + DAS08_STATUS) & DAS08_EOC)) - break; - } - if (i == TIMEOUT) { - printk(KERN_ERR "das08: timeout\n"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das08_ai_eoc, 0); + if (ret) + return ret; + msb = inb(dev->iobase + DAS08_MSB); lsb = inb(dev->iobase + DAS08_LSB); if (thisboard->ai_encoding == das08_encode12) { @@ -594,31 +287,28 @@ static int das08_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, data[0] = 0; data[1] = DAS08_IP(inb(dev->iobase + DAS08_STATUS)); - return 2; + return insn->n; } -static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08_do_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int wbits; - - /* get current settings of digital output lines */ - wbits = (devpriv->do_mux_bits >> 4) & 0xf; - /* null bits we are going to set */ - wbits &= ~data[0]; - /* set new bit values */ - wbits |= data[0] & data[1]; - /* remember digital output bits */ - /* prevent race with setting of analog input mux */ - spin_lock(&dev->spinlock); - devpriv->do_mux_bits &= ~DAS08_DO_MASK; - devpriv->do_mux_bits |= DAS08_OP(wbits); - outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); - spin_unlock(&dev->spinlock); + struct das08_private_struct *devpriv = dev->private; + + if (comedi_dio_update_state(s, data)) { + /* prevent race with setting of analog input mux */ + spin_lock(&dev->spinlock); + devpriv->do_mux_bits &= ~DAS08_DO_MASK; + devpriv->do_mux_bits |= DAS08_OP(s->state); + outb(devpriv->do_mux_bits, dev->iobase + DAS08_CONTROL); + spin_unlock(&dev->spinlock); + } - data[1] = wbits; + data[1] = s->state; - return 2; + return insn->n; } static int das08jr_di_rbits(struct comedi_device *dev, @@ -628,184 +318,108 @@ static int das08jr_di_rbits(struct comedi_device *dev, data[0] = 0; data[1] = inb(dev->iobase + DAS08JR_DIO); - return 2; + return insn->n; } static int das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - /* null bits we are going to set */ - devpriv->do_bits &= ~data[0]; - /* set new bit values */ - devpriv->do_bits |= data[0] & data[1]; - outb(devpriv->do_bits, dev->iobase + DAS08JR_DIO); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS08JR_DIO); - data[1] = devpriv->do_bits; + data[1] = s->state; - return 2; + return insn->n; } -static int das08jr_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void das08_ao_set_data(struct comedi_device *dev, + unsigned int chan, unsigned int data) { - int n; - int lsb, msb; - int chan; - - lsb = data[0] & 0xff; - msb = (data[0] >> 8) & 0xf; - - chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { -#if 0 - outb(lsb, dev->iobase + devpriv->ao_offset_lsb[chan]); - outb(msb, dev->iobase + devpriv->ao_offset_msb[chan]); -#else + const struct das08_board_struct *thisboard = comedi_board(dev); + struct das08_private_struct *devpriv = dev->private; + unsigned char lsb; + unsigned char msb; + + lsb = data & 0xff; + msb = (data >> 8) & 0xff; + if (thisboard->is_jr) { outb(lsb, dev->iobase + DAS08JR_AO_LSB(chan)); outb(msb, dev->iobase + DAS08JR_AO_MSB(chan)); -#endif - /* load DACs */ inb(dev->iobase + DAS08JR_DIO); - } - - return n; -} - -/* - * - * The -aox boards have the DACs at a different offset and use - * a different method to force an update. - * - */ -static int das08ao_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int n; - int lsb, msb; - int chan; - - lsb = data[0] & 0xff; - msb = (data[0] >> 8) & 0xf; - - chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { -#if 0 - outb(lsb, dev->iobase + devpriv->ao_offset_lsb[chan]); - outb(msb, dev->iobase + devpriv->ao_offset_msb[chan]); -#else + } else { outb(lsb, dev->iobase + DAS08AO_AO_LSB(chan)); outb(msb, dev->iobase + DAS08AO_AO_MSB(chan)); -#endif - /* load DACs */ inb(dev->iobase + DAS08AO_AO_UPDATE); } - - return n; + devpriv->ao_readback[chan] = data; } -static unsigned int i8254_read_channel_low(unsigned int base, int chan) +static void das08_ao_initialize(struct comedi_device *dev, + struct comedi_subdevice *s) { - unsigned int msb, lsb; - - /* The following instructions must be in order. - We must avoid other process reading the counter's value in the - middle. - The spin_lock isn't needed since ioctl calls grab the big kernel - lock automatically */ - /*spin_lock(sp); */ - outb(chan << 6, base + I8254_CTRL); - base += chan; - lsb = inb(base); - msb = inb(base); - /*spin_unlock(sp); */ - - return lsb | (msb << 8); -} + int n; + unsigned int data; -static void i8254_write_channel_low(unsigned int base, int chan, - unsigned int value) -{ - unsigned int msb, lsb; - - lsb = value & 0xFF; - msb = value >> 8; - - /* write lsb, then msb */ - base += chan; - /* See comments in i8254_read_channel_low */ - /*spin_lock(sp); */ - outb(lsb, base); - outb(msb, base); - /*spin_unlock(sp); */ + 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 unsigned int i8254_read_channel(struct i8254_struct *st, int channel) +static int das08_ao_winsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int chan = st->logic2phys[channel]; + unsigned int n; + unsigned int chan; - return i8254_read_channel_low(st->iobase, chan); -} - -static void i8254_write_channel(struct i8254_struct *st, int channel, - unsigned int value) -{ - int chan = st->logic2phys[channel]; + chan = CR_CHAN(insn->chanspec); - i8254_write_channel_low(st->iobase, chan, value); -} + for (n = 0; n < insn->n; n++) + das08_ao_set_data(dev, chan, *data); -static void i8254_initialize(struct i8254_struct *st) -{ - int i; - for (i = 0; i < 3; ++i) - i8254_set_mode_low(st->iobase, i, st->mode[i]); + return n; } -static void i8254_set_mode_low(unsigned int base, int channel, - unsigned int mode) +static int das08_ao_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - outb((channel << 6) | 0x30 | (mode & 0x0F), base + I8254_CTRL); -} + struct das08_private_struct *devpriv = dev->private; + unsigned int n; + unsigned int chan; -static void i8254_set_mode(struct i8254_struct *st, int channel, - unsigned int mode) -{ - int chan = st->logic2phys[channel]; + chan = CR_CHAN(insn->chanspec); - st->mode[chan] = mode; - return i8254_set_mode_low(st->iobase, chan, mode); -} + for (n = 0; n < insn->n; n++) + data[n] = devpriv->ao_readback[chan]; -static unsigned int i8254_read_status_low(unsigned int base, int channel) -{ - outb(0xE0 | (2 << channel), base + I8254_CTRL); - return inb(base + channel); + return n; } -static unsigned int i8254_read_status(struct i8254_struct *st, int channel) +static void i8254_initialize(struct comedi_device *dev) { - int chan = st->logic2phys[channel]; + const struct das08_board_struct *thisboard = comedi_board(dev); + unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; + unsigned int mode = I8254_MODE0 | I8254_BINARY; + int i; - return i8254_read_status_low(st->iobase, chan); + for (i = 0; i < 3; ++i) + i8254_set_mode(i8254_iobase, 0, i, mode); } 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); + unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; - /* printk("Reading counter channel %d ",chan); */ - data[0] = i8254_read_channel(&devpriv->i8254, chan); - /* printk("=> 0x%08X\n",data[0]); */ - + data[0] = i8254_read(i8254_iobase, 0, chan); return 1; } @@ -813,11 +427,11 @@ 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); + unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; - /* printk("Writing counter channel %d with 0x%04X\n",chan,data[0]); */ - i8254_write_channel(&devpriv->i8254, chan, data[0]); - + i8254_write(i8254_iobase, 0, chan, data[0]); return 1; } @@ -825,17 +439,16 @@ 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); + unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; - if (insn->n != 2) - return -EINVAL; - switch (data[0]) { case INSN_CONFIG_SET_COUNTER_MODE: - i8254_set_mode(&devpriv->i8254, chan, data[1]); + i8254_set_mode(i8254_iobase, 0, chan, data[1]); break; case INSN_CONFIG_8254_READ_STATUS: - data[1] = i8254_read_status(&devpriv->i8254, chan); + data[1] = i8254_status(i8254_iobase, 0, chan); break; default: return -EINVAL; @@ -844,42 +457,24 @@ static int das08_counter_config(struct comedi_device *dev, return 2; } -static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it); - -static struct comedi_driver driver_das08 = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = das08_attach, - .detach = das08_common_detach, - .board_name = &das08_boards[0].name, - .num_names = sizeof(das08_boards) / sizeof(struct das08_board_struct), - .offset = sizeof(struct das08_board_struct), -}; - int das08_common_attach(struct comedi_device *dev, unsigned long iobase) { + const struct das08_board_struct *thisboard = comedi_board(dev); + struct das08_private_struct *devpriv = dev->private; struct comedi_subdevice *s; int ret; - /* allocate ioports for non-pcmcia, non-pci boards */ - if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) { - printk(KERN_INFO " iobase 0x%lx\n", iobase); - if (!request_region(iobase, thisboard->iosize, DRV_NAME)) { - printk(KERN_ERR " I/O port conflict\n"); - return -EIO; - } - } dev->iobase = iobase; dev->board_name = thisboard->name; - ret = alloc_subdevices(dev, 6); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 6); + if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai */ - if (thisboard->ai) { + if (thisboard->ai_nbits) { s->type = COMEDI_SUBD_AI; /* XXX some boards actually have differential * inputs instead of single ended. @@ -890,63 +485,67 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->n_chan = 8; s->maxdata = (1 << thisboard->ai_nbits) - 1; s->range_table = das08_ai_lranges[thisboard->ai_pg]; - s->insn_read = thisboard->ai; + s->insn_read = das08_ai_rinsn; devpriv->pg_gainlist = das08_gainlists[thisboard->ai_pg]; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao */ - if (thisboard->ao) { + if (thisboard->ao_nbits) { s->type = COMEDI_SUBD_AO; -/* XXX lacks read-back insn */ s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = (1 << thisboard->ao_nbits) - 1; s->range_table = &range_bipolar5; - s->insn_write = thisboard->ao; + s->insn_write = das08_ao_winsn; + s->insn_read = das08_ao_rinsn; + das08_ao_initialize(dev, s); } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* di */ - if (thisboard->di) { + if (thisboard->di_nchan) { s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; - s->n_chan = (thisboard->di == das08_di_rbits) ? 3 : 8; + s->n_chan = thisboard->di_nchan; s->maxdata = 1; s->range_table = &range_digital; - s->insn_bits = thisboard->di; + s->insn_bits = + thisboard->is_jr ? das08jr_di_rbits : das08_di_rbits; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* do */ - if (thisboard->do_) { + if (thisboard->do_nchan) { s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = thisboard->do_nchan; s->maxdata = 1; s->range_table = &range_digital; - s->insn_bits = thisboard->do_; + s->insn_bits = + thisboard->is_jr ? das08jr_do_wbits : das08_do_wbits; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 4; + s = &dev->subdevices[4]; /* 8255 */ if (thisboard->i8255_offset != 0) { - subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase + - thisboard-> - i8255_offset)); + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + thisboard->i8255_offset); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 5; + s = &dev->subdevices[5]; /* 8254 */ if (thisboard->i8254_offset != 0) { s->type = COMEDI_SUBD_COUNTER; @@ -956,16 +555,7 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->insn_read = das08_counter_read; s->insn_write = das08_counter_write; s->insn_config = das08_counter_config; - /* Set-up the 8254 structure */ - devpriv->i8254.channels = 3; - devpriv->i8254.logic2phys[0] = 0; - devpriv->i8254.logic2phys[1] = 1; - devpriv->i8254.logic2phys[2] = 2; - devpriv->i8254.iobase = iobase + thisboard->i8254_offset; - devpriv->i8254.mode[0] = - devpriv->i8254.mode[1] = - devpriv->i8254.mode[2] = I8254_MODE0 | I8254_BINARY; - i8254_initialize(&devpriv->i8254); + i8254_initialize(dev); } else { s->type = COMEDI_SUBD_UNUSED; } @@ -974,167 +564,16 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) } EXPORT_SYMBOL_GPL(das08_common_attach); -static int das08_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - int ret; - unsigned long iobase; -#ifdef CONFIG_COMEDI_PCI - unsigned long pci_iobase = 0; - struct pci_dev *pdev = NULL; -#endif - - ret = alloc_private(dev, sizeof(struct das08_private_struct)); - if (ret < 0) - return ret; - - printk(KERN_INFO "comedi%d: das08: ", dev->minor); - /* deal with a pci board */ - if (thisboard->bustype == pci) { -#ifdef CONFIG_COMEDI_PCI - if (it->options[0] || it->options[1]) { - printk("bus %i slot %i ", - it->options[0], it->options[1]); - } - printk("\n"); - /* find card */ - for_each_pci_dev(pdev) { - if (pdev->vendor == PCI_VENDOR_ID_COMPUTERBOARDS - && pdev->device == PCI_DEVICE_ID_PCIDAS08) { - if (it->options[0] || it->options[1]) { - if (pdev->bus->number == it->options[0] - && PCI_SLOT(pdev->devfn) == - it->options[1]) { - break; - } - } else { - break; - } - } - } - if (!pdev) { - printk(KERN_ERR "No pci das08 cards found\n"); - return -EIO; - } - devpriv->pdev = pdev; - /* enable PCI device and reserve I/O spaces */ - if (comedi_pci_enable(pdev, DRV_NAME)) { - printk(KERN_ERR " Error enabling PCI device and " - "requesting regions\n"); - return -EIO; - } - /* read base addresses */ - pci_iobase = pci_resource_start(pdev, 1); - iobase = pci_resource_start(pdev, 2); - printk(KERN_INFO "pcibase 0x%lx iobase 0x%lx\n", - pci_iobase, iobase); - devpriv->pci_iobase = pci_iobase; -#if 0 -/* We could enable to pci-das08's interrupt here to make it possible - * to do timed input in this driver, but there is little point since - * conversions would have to be started by the interrupt handler - * so you might as well use comedi_rt_timer to emulate commands - */ - /* set source of interrupt trigger to counter2 output */ - outb(CNTRL_INTR | CNTRL_DIR, pci_iobase + CNTRL); - /* Enable local interrupt 1 and pci interrupt */ - outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR); -#endif -#else /* CONFIG_COMEDI_PCI */ - printk(KERN_ERR "this driver has not been built with PCI support.\n"); - return -EINVAL; -#endif /* CONFIG_COMEDI_PCI */ - } else { - iobase = it->options[0]; - } - printk(KERN_INFO "\n"); - - return das08_common_attach(dev, iobase); -} - - -int das08_common_detach(struct comedi_device *dev) +static int __init das08_init(void) { - printk(KERN_INFO "comedi%d: das08: remove\n", dev->minor); - - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 4); - - /* deallocate ioports for non-pcmcia, non-pci boards */ - if ((thisboard->bustype != pcmcia) && (thisboard->bustype != pci)) { - if (dev->iobase) - release_region(dev->iobase, thisboard->iosize); - } -#ifdef CONFIG_COMEDI_PCI - if (devpriv) { - if (devpriv->pdev) { - if (devpriv->pci_iobase) - comedi_pci_disable(devpriv->pdev); - - pci_dev_put(devpriv->pdev); - } - } -#endif - return 0; } -EXPORT_SYMBOL_GPL(das08_common_detach); - -#ifdef CONFIG_COMEDI_PCI -static int __devinit driver_das08_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_das08.driver_name); -} - -static void __devexit driver_das08_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_das08_pci_driver = { - .id_table = das08_pci_table, - .probe = &driver_das08_pci_probe, - .remove = __devexit_p(&driver_das08_pci_remove) -}; +module_init(das08_init); -static int __init driver_das08_init_module(void) +static void __exit das08_exit(void) { - int retval; - - retval = comedi_driver_register(&driver_das08); - if (retval < 0) - return retval; - - driver_das08_pci_driver.name = (char *)driver_das08.driver_name; - return pci_register_driver(&driver_das08_pci_driver); } - -static void __exit driver_das08_cleanup_module(void) -{ - pci_unregister_driver(&driver_das08_pci_driver); - comedi_driver_unregister(&driver_das08); -} - -module_init(driver_das08_init_module); -module_exit(driver_das08_cleanup_module); -#else -static int __init driver_das08_init_module(void) -{ - return comedi_driver_register(&driver_das08); -} - -static void __exit driver_das08_cleanup_module(void) -{ - comedi_driver_unregister(&driver_das08); -} - -module_init(driver_das08_init_module); -module_exit(driver_das08_cleanup_module); -#endif - -#ifdef CONFIG_COMEDI_PCMCIA -EXPORT_SYMBOL_GPL(das08_cs_boards); -#endif +module_exit(das08_exit); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index 2a30d764ddf..18cc170facd 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -14,17 +14,11 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _DAS08_H #define _DAS08_H -enum das08_bustype { isa, pci, pcmcia, pc104 }; /* different ways ai data is encoded in first two registers */ enum das08_ai_encoding { das08_encode12, das08_encode16, das08_pcm_encode12 }; enum das08_lrange { das08_pg_none, das08_bipolar5, das08_pgh, das08_pgl, @@ -33,47 +27,26 @@ enum das08_lrange { das08_pg_none, das08_bipolar5, das08_pgh, das08_pgl, struct das08_board_struct { const char *name; - unsigned int id; /* id for pci/pcmcia boards */ - enum das08_bustype bustype; - void *ai; + bool is_jr; /* true for 'JR' boards */ unsigned int ai_nbits; enum das08_lrange ai_pg; enum das08_ai_encoding ai_encoding; - void *ao; unsigned int ao_nbits; - void *di; - void *do_; + unsigned int di_nchan; unsigned int do_nchan; unsigned int i8255_offset; unsigned int i8254_offset; unsigned int iosize; /* number of ioports used */ }; -struct i8254_struct { - int channels; /* available channels. Some could be used internally. */ - int logic2phys[3]; /* to know which physical channel is. */ - int mode[3]; /* the index is the real counter. */ - unsigned int iobase; -}; - -#define I8254_CNT0 0 -#define I8254_CNT1 1 -#define I8254_CNT2 2 -#define I8254_CTRL 3 - struct das08_private_struct { - unsigned int do_mux_bits; /* bits for do/mux register on boards without separate do register */ - unsigned int do_bits; /* bits for do register on boards with register dedicated to digital out only */ + unsigned int do_mux_bits; /* bits for do/mux register on boards + * without separate do register + */ const unsigned int *pg_gainlist; - struct pci_dev *pdev; /* struct for pci-das08 */ - unsigned int pci_iobase; /* additional base address for pci-das08 */ - struct i8254_struct i8254; + unsigned int ao_readback[2]; /* assume 2 AO channels */ }; -#define NUM_DAS08_CS_BOARDS 2 -extern struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS]; - int das08_common_attach(struct comedi_device *dev, unsigned long iobase); -int das08_common_detach(struct comedi_device *dev); #endif /* _DAS08_H */ diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index 6d91d302817..f3ccc2ce6d4 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -16,12 +16,12 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -***************************************************************** + PCMCIA support code for this driver is adapted from the dummy_cs.c + driver of the Linux PCMCIA Card Services package. + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. */ /* Driver: das08_cs @@ -39,235 +39,79 @@ Options (for pcm-das08): Command support does not exist, but could be added for this board. */ -#include "../comedidev.h" - -#include <linux/delay.h> -#include <linux/pci.h> -#include <linux/slab.h> +#include <linux/module.h> -#include "das08.h" +#include "../comedidev.h" -/* pcmcia includes */ #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> -static struct pcmcia_device *cur_dev; - -#define thisboard ((const struct das08_board_struct *)dev->board_ptr) - -static int das08_cs_attach(struct comedi_device *dev, - struct comedi_devconfig *it); +#include "das08.h" -static struct comedi_driver driver_das08_cs = { - .driver_name = "das08_cs", - .module = THIS_MODULE, - .attach = das08_cs_attach, - .detach = das08_common_detach, - .board_name = &das08_cs_boards[0].name, - .num_names = ARRAY_SIZE(das08_cs_boards), - .offset = sizeof(struct das08_board_struct), +static const struct das08_board_struct das08_cs_boards[] = { + { + .name = "pcm-das08", + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_pcm_encode12, + .di_nchan = 3, + .do_nchan = 3, + .iosize = 16, + }, }; -static int das08_cs_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int das08_cs_auto_attach(struct comedi_device *dev, + unsigned long context) { - int ret; + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + struct das08_private_struct *devpriv; unsigned long iobase; - struct pcmcia_device *link = cur_dev; /* XXX hack */ - - ret = alloc_private(dev, sizeof(struct das08_private_struct)); - if (ret < 0) - return ret; + int ret; - printk("comedi%d: das08_cs: ", dev->minor); - /* deal with a pci board */ + /* The das08 driver needs the board_ptr */ + dev->board_ptr = &das08_cs_boards[0]; - if (thisboard->bustype == pcmcia) { - if (link == NULL) { - printk(" no pcmcia cards found\n"); - return -EIO; - } - iobase = link->resource[0]->start; - } else { - printk(" bug! board does not have PCMCIA bustype\n"); - return -EINVAL; - } + link->config_flags |= CONF_AUTO_SET_IO; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; + iobase = link->resource[0]->start; - printk("\n"); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; return das08_common_attach(dev, iobase); } -/*====================================================================== - - The following pcmcia code for the pcm-das08 is adapted from the - dummy_cs.c driver of the Linux PCMCIA Card Services package. - - The initial developer of the original code is David A. Hinds - <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - -======================================================================*/ - -static void das08_pcmcia_config(struct pcmcia_device *link); -static void das08_pcmcia_release(struct pcmcia_device *link); -static int das08_pcmcia_suspend(struct pcmcia_device *p_dev); -static int das08_pcmcia_resume(struct pcmcia_device *p_dev); - -static int das08_pcmcia_attach(struct pcmcia_device *); -static void das08_pcmcia_detach(struct pcmcia_device *); - -struct local_info_t { - struct pcmcia_device *link; - int stop; - struct bus_operations *bus; +static struct comedi_driver driver_das08_cs = { + .driver_name = "das08_cs", + .module = THIS_MODULE, + .auto_attach = das08_cs_auto_attach, + .detach = comedi_pcmcia_disable, }; static int das08_pcmcia_attach(struct pcmcia_device *link) { - struct local_info_t *local; - - dev_dbg(&link->dev, "das08_pcmcia_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - local->link = link; - link->priv = local; - - cur_dev = link; - - das08_pcmcia_config(link); - - return 0; -} /* das08_pcmcia_attach */ - -static void das08_pcmcia_detach(struct pcmcia_device *link) -{ - - dev_dbg(&link->dev, "das08_pcmcia_detach\n"); - - ((struct local_info_t *)link->priv)->stop = 1; - das08_pcmcia_release(link); - - /* This points to the parent struct local_info_t struct */ - kfree(link->priv); - -} /* das08_pcmcia_detach */ - - -static int das08_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); + return comedi_pcmcia_auto_config(link, &driver_das08_cs); } -static void das08_pcmcia_config(struct pcmcia_device *link) -{ - int ret; - - dev_dbg(&link->dev, "das08_pcmcia_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, das08_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - return; - -failed: - das08_pcmcia_release(link); - -} /* das08_pcmcia_config */ - -static void das08_pcmcia_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "das08_pcmcia_release\n"); - pcmcia_disable_device(link); -} /* das08_pcmcia_release */ - -static int das08_pcmcia_suspend(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - /* Mark the device as stopped, to block IO until later */ - local->stop = 1; - - return 0; -} /* das08_pcmcia_suspend */ - -static int das08_pcmcia_resume(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - local->stop = 0; - return 0; -} /* das08_pcmcia_resume */ - -/*====================================================================*/ - static const struct pcmcia_device_id das08_cs_id_table[] = { PCMCIA_DEVICE_MANF_CARD(0x01c5, 0x4001), PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, das08_cs_id_table); + +static struct pcmcia_driver das08_cs_driver = { + .name = "pcm-das08", + .owner = THIS_MODULE, + .id_table = das08_cs_id_table, + .probe = das08_pcmcia_attach, + .remove = comedi_pcmcia_auto_unconfig, +}; +module_comedi_pcmcia_driver(driver_das08_cs, das08_cs_driver); + MODULE_AUTHOR("David A. Schleef <ds@schleef.org>, " "Frank Mori Hess <fmhess@users.sourceforge.net>"); MODULE_DESCRIPTION("Comedi driver for ComputerBoards DAS-08 PCMCIA boards"); MODULE_LICENSE("GPL"); - -struct pcmcia_driver das08_cs_driver = { - .probe = das08_pcmcia_attach, - .remove = das08_pcmcia_detach, - .suspend = das08_pcmcia_suspend, - .resume = das08_pcmcia_resume, - .id_table = das08_cs_id_table, - .owner = THIS_MODULE, - .name = "pcm-das08", -}; - -static int __init init_das08_pcmcia_cs(void) -{ - pcmcia_register_driver(&das08_cs_driver); - return 0; -} - -static void __exit exit_das08_pcmcia_cs(void) -{ - pr_debug("das08_pcmcia_cs: unloading\n"); - pcmcia_unregister_driver(&das08_cs_driver); -} - -static int __init das08_cs_init_module(void) -{ - int ret; - - ret = init_das08_pcmcia_cs(); - if (ret < 0) - return ret; - - return comedi_driver_register(&driver_das08_cs); -} - -static void __exit das08_cs_exit_module(void) -{ - exit_das08_pcmcia_cs(); - comedi_driver_unregister(&driver_das08_cs); -} - -module_init(das08_cs_init_module); -module_exit(das08_cs_exit_module); diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c new file mode 100644 index 00000000000..4fb03d3852d --- /dev/null +++ b/drivers/staging/comedi/drivers/das08_isa.c @@ -0,0 +1,205 @@ +/* + * das08_isa.c + * comedi driver for DAS08 ISA/PC-104 boards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * Copyright (C) 2001,2002,2003 Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2004 Salvador E. Tropea <set@users.sf.net> <set@ieee.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: das08_isa + * Description: DAS-08 ISA/PC-104 compatible boards + * Devices: (Keithley Metrabyte) DAS08 [isa-das08], + * (ComputerBoards) DAS08 [isa-das08] + * (ComputerBoards) DAS08-PGM [das08-pgm] + * (ComputerBoards) DAS08-PGH [das08-pgh] + * (ComputerBoards) DAS08-PGL [das08-pgl] + * (ComputerBoards) DAS08-AOH [das08-aoh] + * (ComputerBoards) DAS08-AOL [das08-aol] + * (ComputerBoards) DAS08-AOM [das08-aom] + * (ComputerBoards) DAS08/JR-AO [das08/jr-ao] + * (ComputerBoards) DAS08/JR-16-AO [das08jr-16-ao] + * (ComputerBoards) PC104-DAS08 [pc104-das08] + * (ComputerBoards) DAS08/JR/16 [das08jr/16] + * Author: Warren Jasper, ds, Frank Hess + * Updated: Fri, 31 Aug 2012 19:19:06 +0100 + * Status: works + * + * This is the ISA/PC-104-specific support split off from the das08 driver. + * + * Configuration Options: + * [0] - base io address + */ + +#include <linux/module.h> +#include "../comedidev.h" + +#include "das08.h" + +static const struct das08_board_struct das08_isa_boards[] = { + { + /* cio-das08.pdf */ + .name = "isa-das08", + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 8, + .i8254_offset = 4, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08pgx.pdf */ + .name = "das08-pgm", + .ai_nbits = 12, + .ai_pg = das08_pgm, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 0, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08pgx.pdf */ + .name = "das08-pgh", + .ai_nbits = 12, + .ai_pg = das08_pgh, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08pgx.pdf */ + .name = "das08-pgl", + .ai_nbits = 12, + .ai_pg = das08_pgl, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08_aox.pdf */ + .name = "das08-aoh", + .ai_nbits = 12, + .ai_pg = das08_pgh, + .ai_encoding = das08_encode12, + .ao_nbits = 12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08_aox.pdf */ + .name = "das08-aol", + .ai_nbits = 12, + .ai_pg = das08_pgl, + .ai_encoding = das08_encode12, + .ao_nbits = 12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08_aox.pdf */ + .name = "das08-aom", + .ai_nbits = 12, + .ai_pg = das08_pgm, + .ai_encoding = das08_encode12, + .ao_nbits = 12, + .di_nchan = 3, + .do_nchan = 4, + .i8255_offset = 0x0c, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08-jr-ao.pdf */ + .name = "das08/jr-ao", + .is_jr = true, + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .ao_nbits = 12, + .di_nchan = 8, + .do_nchan = 8, + .iosize = 16, /* unchecked */ + }, { + /* cio-das08jr-16-ao.pdf */ + .name = "das08jr-16-ao", + .is_jr = true, + .ai_nbits = 16, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode16, + .ao_nbits = 16, + .di_nchan = 8, + .do_nchan = 8, + .i8254_offset = 0x04, + .iosize = 16, /* unchecked */ + }, { + .name = "pc104-das08", + .ai_nbits = 12, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8254_offset = 4, + .iosize = 16, /* unchecked */ + }, { + .name = "das08jr/16", + .is_jr = true, + .ai_nbits = 16, + .ai_pg = das08_pg_none, + .ai_encoding = das08_encode16, + .di_nchan = 8, + .do_nchan = 8, + .iosize = 16, /* unchecked */ + }, +}; + +static int das08_isa_attach(struct comedi_device *dev, + struct comedi_devconfig *it) +{ + const struct das08_board_struct *thisboard = comedi_board(dev); + struct das08_private_struct *devpriv; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], thisboard->iosize); + if (ret) + return ret; + + return das08_common_attach(dev, dev->iobase); +} + +static struct comedi_driver das08_isa_driver = { + .driver_name = "isa-das08", + .module = THIS_MODULE, + .attach = das08_isa_attach, + .detach = comedi_legacy_detach, + .board_name = &das08_isa_boards[0].name, + .num_names = ARRAY_SIZE(das08_isa_boards), + .offset = sizeof(das08_isa_boards[0]), +}; +module_comedi_driver(das08_isa_driver); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c new file mode 100644 index 00000000000..d94af09151b --- /dev/null +++ b/drivers/staging/comedi/drivers/das08_pci.c @@ -0,0 +1,108 @@ +/* + * das08_pci.c + * comedi driver for DAS08 PCI boards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * Copyright (C) 2001,2002,2003 Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2004 Salvador E. Tropea <set@users.sf.net> <set@ieee.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: das08_pci + * Description: DAS-08 PCI compatible boards + * Devices: (ComputerBoards) PCI-DAS08 [pci-das08] + * Author: Warren Jasper, ds, Frank Hess + * Updated: Fri, 31 Aug 2012 19:19:06 +0100 + * Status: works + * + * This is the PCI-specific support split off from the das08 driver. + * + * Configuration Options: not applicable, uses PCI auto config + */ + +#include <linux/module.h> +#include <linux/pci.h> + +#include "../comedidev.h" + +#include "das08.h" + +#define PCI_DEVICE_ID_PCIDAS08 0x0029 + +static const struct das08_board_struct das08_pci_boards[] = { + { + .name = "pci-das08", + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_encode12, + .di_nchan = 3, + .do_nchan = 4, + .i8254_offset = 4, + .iosize = 8, + }, +}; + +static int das08_pci_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pdev = comedi_to_pci_dev(dev); + struct das08_private_struct *devpriv; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + /* The das08 driver needs the board_ptr */ + dev->board_ptr = &das08_pci_boards[0]; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pdev, 2); + + return das08_common_attach(dev, dev->iobase); +} + +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, +}; + +static int das08_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &das08_pci_comedi_driver, + id->driver_data); +} + +static const struct pci_device_id das08_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_PCIDAS08) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, das08_pci_table); + +static struct pci_driver das08_pci_driver = { + .name = "pci-das08", + .id_table = das08_pci_table, + .probe = das08_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(das08_pci_comedi_driver, das08_pci_driver); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index e7905bac92d..2feecf199f2 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -1,302 +1,205 @@ /* - comedi/drivers/das16.c - DAS16 driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com> - Copyright (C) 2001,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 - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * das16.c + * DAS16 driver + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com> + * Copyright (C) 2001,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 + * 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: das16 -Description: DAS16 compatible boards -Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze -Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g), - DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202), - DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601), - DAS-1602 (das-1602), - [ComputerBoards] PC104-DAS16/JR (pc104-das16jr), - PC104-DAS16JR/16 (pc104-das16jr/16), - CIO-DAS16JR/16 (cio-das16jr/16), - CIO-DAS16/JR (cio-das16/jr), CIO-DAS1401/12 (cio-das1401/12), - CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16), - CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12), - CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330) -Status: works -Updated: 2003-10-12 - -A rewrite of the das16 and das1600 drivers. -Options: - [0] - base io address - [1] - irq (does nothing, irq is not used anymore) - [2] - dma (optional, required for comedi_command support) - [3] - master clock speed in MHz (optional, 1 or 10, ignored if - board can probe clock, defaults to 1) - [4] - analog input range lowest voltage in microvolts (optional, - only useful if your board does not have software - programmable gain) - [5] - analog input range highest voltage in microvolts (optional, - only useful if board does not have software programmable - gain) - [6] - analog output range lowest voltage in microvolts (optional) - [7] - analog output range highest voltage in microvolts (optional) - [8] - use timer mode for DMA. Timer mode is needed e.g. for - buggy DMA controllers in NS CS5530A (Geode Companion), and for - 'jr' cards that lack a hardware fifo. This option is no - longer needed, since timer mode is _always_ used. - -Passing a zero for an option is the same as leaving it unspecified. + * Driver: das16 + * Description: DAS16 compatible boards + * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze + * Devices: (Keithley Metrabyte) DAS-16 [das-16] + * (Keithley Metrabyte) DAS-16G [das-16g] + * (Keithley Metrabyte) DAS-16F [das-16f] + * (Keithley Metrabyte) DAS-1201 [das-1201] + * (Keithley Metrabyte) DAS-1202 [das-1202] + * (Keithley Metrabyte) DAS-1401 [das-1401] + * (Keithley Metrabyte) DAS-1402 [das-1402] + * (Keithley Metrabyte) DAS-1601 [das-1601] + * (Keithley Metrabyte) DAS-1602 [das-1602] + * (ComputerBoards) PC104-DAS16/JR [pc104-das16jr] + * (ComputerBoards) PC104-DAS16JR/16 [pc104-das16jr/16] + * (ComputerBoards) CIO-DAS16 [cio-das16] + * (ComputerBoards) CIO-DAS16F [cio-das16/f] + * (ComputerBoards) CIO-DAS16/JR [cio-das16/jr] + * (ComputerBoards) CIO-DAS16JR/16 [cio-das16jr/16] + * (ComputerBoards) CIO-DAS1401/12 [cio-das1401/12] + * (ComputerBoards) CIO-DAS1402/12 [cio-das1402/12] + * (ComputerBoards) CIO-DAS1402/16 [cio-das1402/16] + * (ComputerBoards) CIO-DAS1601/12 [cio-das1601/12] + * (ComputerBoards) CIO-DAS1602/12 [cio-das1602/12] + * (ComputerBoards) CIO-DAS1602/16 [cio-das1602/16] + * (ComputerBoards) CIO-DAS16/330 [cio-das16/330] + * Status: works + * Updated: 2003-10-12 + * + * A rewrite of the das16 and das1600 drivers. + * + * Options: + * [0] - base io address + * [1] - irq (does nothing, irq is not used anymore) + * [2] - dma channel (optional, required for comedi_command support) + * [3] - master clock speed in MHz (optional, 1 or 10, ignored if + * board can probe clock, defaults to 1) + * [4] - analog input range lowest voltage in microvolts (optional, + * only useful if your board does not have software + * programmable gain) + * [5] - analog input range highest voltage in microvolts (optional, + * only useful if board does not have software programmable + * gain) + * [6] - analog output range lowest voltage in microvolts (optional) + * [7] - analog output range highest voltage in microvolts (optional) + * + * Passing a zero for an option is the same as leaving it unspecified. + */ -*/ /* + * Testing and debugging help provided by Daniel Koch. + * + * Keithley Manuals: + * 2309.PDF (das16) + * 4919.PDF (das1400, 1600) + * 4922.PDF (das-1400) + * 4923.PDF (das1200, 1400, 1600) + * + * Computer boards manuals also available from their website + * www.measurementcomputing.com + */ -Testing and debugging help provided by Daniel Koch. - -Keithley Manuals: - 2309.PDF (das16) - 4919.PDF (das1400, 1600) - 4922.PDF (das-1400) - 4923.PDF (das1200, 1400, 1600) - -Computer boards manuals also available from their website -www.measurementcomputing.com - -*/ - -#include <linux/pci.h> +#include <linux/module.h> #include <linux/slab.h> +#include <linux/delay.h> +#include <linux/pci.h> #include <linux/interrupt.h> + #include <asm/dma.h> + #include "../comedidev.h" #include "8253.h" #include "8255.h" #include "comedi_fc.h" -#undef DEBUG -/* #define DEBUG */ - -#ifdef DEBUG -#define DEBUG_PRINT(format, args...) \ - printk(KERN_DEBUG "das16: " format, ## args) -#else -#define DEBUG_PRINT(format, args...) -#endif - -#define DAS16_SIZE 20 /* number of ioports */ #define DAS16_DMA_SIZE 0xff00 /* size in bytes of allocated dma buffer */ /* - cio-das16.pdf - - "das16" - "das16/f" - - 0 a/d bits 0-3 start 12 bit - 1 a/d bits 4-11 unused - 2 mux read mux set - 3 di 4 bit do 4 bit - 4 unused ao0_lsb - 5 unused ao0_msb - 6 unused ao1_lsb - 7 unused ao1_msb - 8 status eoc uni/bip interrupt reset - 9 dma, int, trig ctrl set dma, int - a pacer control unused - b reserved reserved - cdef 8254 - 0123 8255 - -*/ - -/* - cio-das16jr.pdf - - "das16jr" - - 0 a/d bits 0-3 start 12 bit - 1 a/d bits 4-11 unused - 2 mux read mux set - 3 di 4 bit do 4 bit - 4567 unused unused - 8 status eoc uni/bip interrupt reset - 9 dma, int, trig ctrl set dma, int - a pacer control unused - b gain status gain control - cdef 8254 - -*/ - -/* - cio-das16jr_16.pdf - - "das16jr_16" - - 0 a/d bits 0-7 start 16 bit - 1 a/d bits 8-15 unused - 2 mux read mux set - 3 di 4 bit do 4 bit - 4567 unused unused - 8 status eoc uni/bip interrupt reset - 9 dma, int, trig ctrl set dma, int - a pacer control unused - b gain status gain control - cdef 8254 - -*/ -/* - cio-das160x-1x.pdf - - "das1601/12" - "das1602/12" - "das1602/16" - - 0 a/d bits 0-3 start 12 bit - 1 a/d bits 4-11 unused - 2 mux read mux set - 3 di 4 bit do 4 bit - 4 unused ao0_lsb - 5 unused ao0_msb - 6 unused ao1_lsb - 7 unused ao1_msb - 8 status eoc uni/bip interrupt reset - 9 dma, int, trig ctrl set dma, int - a pacer control unused - b gain status gain control - cdef 8254 - 400 8255 - 404 unused conversion enable - 405 unused burst enable - 406 unused das1600 enable - 407 status - -*/ - -/* size in bytes of a sample from board */ -static const int sample_size = 2; - -#define DAS16_TRIG 0 -#define DAS16_AI_LSB 0 -#define DAS16_AI_MSB 1 -#define DAS16_MUX 2 -#define DAS16_DIO 3 -#define DAS16_AO_LSB(x) ((x) ? 6 : 4) -#define DAS16_AO_MSB(x) ((x) ? 7 : 5) -#define DAS16_STATUS 8 -#define BUSY (1<<7) -#define UNIPOLAR (1<<6) -#define DAS16_MUXBIT (1<<5) -#define DAS16_INT (1<<4) -#define DAS16_CONTROL 9 -#define DAS16_INTE (1<<7) -#define DAS16_IRQ(x) (((x) & 0x7) << 4) -#define DMA_ENABLE (1<<2) -#define PACING_MASK 0x3 -#define INT_PACER 0x03 -#define EXT_PACER 0x02 -#define DAS16_SOFT 0x00 -#define DAS16_PACER 0x0A -#define DAS16_CTR0 (1<<1) -#define DAS16_TRIG0 (1<<0) -#define BURST_LEN_BITS(x) (((x) & 0xf) << 4) -#define DAS16_GAIN 0x0B -#define DAS16_CNTR0_DATA 0x0C -#define DAS16_CNTR1_DATA 0x0D -#define DAS16_CNTR2_DATA 0x0E -#define DAS16_CNTR_CONTROL 0x0F -#define DAS16_TERM_CNT 0x00 -#define DAS16_ONE_SHOT 0x02 -#define DAS16_RATE_GEN 0x04 -#define DAS16_CNTR_LSB_MSB 0x30 -#define DAS16_CNTR0 0x00 -#define DAS16_CNTR1 0x40 -#define DAS16_CNTR2 0x80 - -#define DAS1600_CONV 0x404 -#define DAS1600_CONV_DISABLE 0x40 -#define DAS1600_BURST 0x405 -#define DAS1600_BURST_VAL 0x40 -#define DAS1600_ENABLE 0x406 -#define DAS1600_ENABLE_VAL 0x40 -#define DAS1600_STATUS_B 0x407 -#define DAS1600_BME 0x40 -#define DAS1600_ME 0x20 -#define DAS1600_CD 0x10 -#define DAS1600_WS 0x02 -#define DAS1600_CLK_10MHZ 0x01 - -static const struct comedi_lrange range_das1x01_bip = { 4, { - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - } + * Register I/O map + */ +#define DAS16_TRIG_REG 0x00 +#define DAS16_AI_LSB_REG 0x00 +#define DAS16_AI_MSB_REG 0x01 +#define DAS16_MUX_REG 0x02 +#define DAS16_DIO_REG 0x03 +#define DAS16_AO_LSB_REG(x) ((x) ? 0x06 : 0x04) +#define DAS16_AO_MSB_REG(x) ((x) ? 0x07 : 0x05) +#define DAS16_STATUS_REG 0x08 +#define DAS16_STATUS_BUSY (1 << 7) +#define DAS16_STATUS_UNIPOLAR (1 << 6) +#define DAS16_STATUS_MUXBIT (1 << 5) +#define DAS16_STATUS_INT (1 << 4) +#define DAS16_CTRL_REG 0x09 +#define DAS16_CTRL_INTE (1 << 7) +#define DAS16_CTRL_IRQ(x) (((x) & 0x7) << 4) +#define DAS16_CTRL_DMAE (1 << 2) +#define DAS16_CTRL_PACING_MASK (3 << 0) +#define DAS16_CTRL_INT_PACER (3 << 0) +#define DAS16_CTRL_EXT_PACER (2 << 0) +#define DAS16_CTRL_SOFT_PACER (0 << 0) +#define DAS16_PACER_REG 0x0a +#define DAS16_PACER_BURST_LEN(x) (((x) & 0xf) << 4) +#define DAS16_PACER_CTR0 (1 << 1) +#define DAS16_PACER_TRIG0 (1 << 0) +#define DAS16_GAIN_REG 0x0b +#define DAS16_TIMER_BASE_REG 0x0c /* to 0x0f */ + +#define DAS1600_CONV_REG 0x404 +#define DAS1600_CONV_DISABLE (1 << 6) +#define DAS1600_BURST_REG 0x405 +#define DAS1600_BURST_VAL (1 << 6) +#define DAS1600_ENABLE_REG 0x406 +#define DAS1600_ENABLE_VAL (1 << 6) +#define DAS1600_STATUS_REG 0x407 +#define DAS1600_STATUS_BME (1 << 6) +#define DAS1600_STATUS_ME (1 << 5) +#define DAS1600_STATUS_CD (1 << 4) +#define DAS1600_STATUS_WS (1 << 1) +#define DAS1600_STATUS_CLK_10MHZ (1 << 0) + +static const struct comedi_lrange range_das1x01_bip = { + 4, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_das1x01_unip = { 4, { - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - } +static const struct comedi_lrange range_das1x01_unip = { + 4, { + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01) + } }; -static const struct comedi_lrange range_das1x02_bip = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - } +static const struct comedi_lrange range_das1x02_bip = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } }; -static const struct comedi_lrange range_das1x02_unip = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_das1x02_unip = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_das16jr = { 9, { - /* also used by 16/330 */ - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_das16jr = { + 9, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_das16jr_16 = { 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_das16jr_16 = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 }; @@ -334,56 +237,15 @@ static const struct comedi_lrange *const das16_ai_bip_lranges[] = { &range_das1x02_bip, }; -struct munge_info { - uint8_t byte; - unsigned have_byte:1; -}; - -static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int das16_cmd_exec(struct comedi_device *dev, - struct comedi_subdevice *s); -static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static void das16_ai_munge(struct comedi_device *dev, - struct comedi_subdevice *s, void *array, - unsigned int num_bytes, - unsigned int start_chan_index); - -static void das16_reset(struct comedi_device *dev); -static irqreturn_t das16_dma_interrupt(int irq, void *d); -static void das16_timer_interrupt(unsigned long arg); -static void das16_interrupt(struct comedi_device *dev); - -static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, - int flags); -static int das1600_mode_detect(struct comedi_device *dev); -static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, - struct comedi_cmd cmd); - -static void reg_dump(struct comedi_device *dev); - struct das16_board { const char *name; - void *ai; - unsigned int ai_nbits; + unsigned int ai_maxdata; unsigned int ai_speed; /* max conversion speed in nanosec */ unsigned int ai_pg; - void *ao; - unsigned int ao_nbits; - void *di; - void *do_; + unsigned int has_ao:1; + unsigned int has_8255:1; unsigned int i8255_offset; - unsigned int i8254_offset; unsigned int size; unsigned int id; @@ -391,344 +253,196 @@ struct das16_board { static const struct das16_board das16_boards[] = { { - .name = "das-16", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 15000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, - { - .name = "das-16g", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 15000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, - { - .name = "das-16f", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 8500, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x00, - }, - { - .name = "cio-das16", /* cio-das16.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 20000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x80, - }, - { - .name = "cio-das16/f", /* das16.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_none, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x10, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0x80, - }, - { - .name = "cio-das16/jr", /* cio-das16jr.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 7692, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, - { - .name = "pc104-das16jr", /* pc104-das16jr_xx.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 3300, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, - { - .name = "cio-das16jr/16", /* cio-das16jr_16.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_16jr_16, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, - { - .name = "pc104-das16jr/16", /* pc104-das16jr_xx.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_16jr_16, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x10, - .id = 0x00, - }, - { - .name = "das-1201", /* 4924.pdf (keithley user's manual) */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 20000, - .ai_pg = das16_pg_none, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0x20, - }, - { - .name = "das-1202", /* 4924.pdf (keithley user's manual) */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_none, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0x20, - }, - { - /* 4919.pdf and 4922.pdf (keithley user's manual) */ - .name = "das-1401", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1601, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */ - }, - { - /* 4919.pdf and 4922.pdf (keithley user's manual) */ - .name = "das-1402", - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0 /* 4919.pdf says id bits are 0xe0, 4922.pdf says 0xc0 */ - }, - { - .name = "das-1601", /* 4919.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1601, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "das-1602", /* 4919.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1401/12", /* cio-das1400_series.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1601, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1402/12", /* cio-das1400_series.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1402/16", /* cio-das1400_series.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1601/12", /* cio-das160x-1x.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 6250, - .ai_pg = das16_pg_1601, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1602/12", /* cio-das160x-1x.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das1602/16", /* cio-das160x-1x.pdf */ - .ai = das16_ai_rinsn, - .ai_nbits = 16, - .ai_speed = 10000, - .ai_pg = das16_pg_1602, - .ao = das16_ao_winsn, - .ao_nbits = 12, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0x400, - .i8254_offset = 0x0c, - .size = 0x408, - .id = 0xc0}, - { - .name = "cio-das16/330", /* ? */ - .ai = das16_ai_rinsn, - .ai_nbits = 12, - .ai_speed = 3030, - .ai_pg = das16_pg_16jr, - .ao = NULL, - .di = das16_di_rbits, - .do_ = das16_do_wbits, - .i8255_offset = 0, - .i8254_offset = 0x0c, - .size = 0x14, - .id = 0xf0}, -#if 0 - { - .name = "das16/330i", /* ? */ - }, - { - .name = "das16/jr/ctr5", /* ? */ - }, - { - /* cio-das16_m1_16.pdf, this board is a bit quirky, no dma */ - .name = "cio-das16/m1/16", - }, -#endif -}; - -static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int das16_detach(struct comedi_device *dev); -static struct comedi_driver driver_das16 = { - .driver_name = "das16", - .module = THIS_MODULE, - .attach = das16_attach, - .detach = das16_detach, - .board_name = &das16_boards[0].name, - .num_names = ARRAY_SIZE(das16_boards), - .offset = sizeof(das16_boards[0]), + .name = "das-16", + .ai_maxdata = 0x0fff, + .ai_speed = 15000, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x00, + }, { + .name = "das-16g", + .ai_maxdata = 0x0fff, + .ai_speed = 15000, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x00, + }, { + .name = "das-16f", + .ai_maxdata = 0x0fff, + .ai_speed = 8500, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x00, + }, { + .name = "cio-das16", + .ai_maxdata = 0x0fff, + .ai_speed = 20000, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x80, + }, { + .name = "cio-das16/f", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_none, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x10, + .size = 0x14, + .id = 0x80, + }, { + .name = "cio-das16/jr", + .ai_maxdata = 0x0fff, + .ai_speed = 7692, + .ai_pg = das16_pg_16jr, + .size = 0x10, + .id = 0x00, + }, { + .name = "pc104-das16jr", + .ai_maxdata = 0x0fff, + .ai_speed = 3300, + .ai_pg = das16_pg_16jr, + .size = 0x10, + .id = 0x00, + }, { + .name = "cio-das16jr/16", + .ai_maxdata = 0xffff, + .ai_speed = 10000, + .ai_pg = das16_pg_16jr_16, + .size = 0x10, + .id = 0x00, + }, { + .name = "pc104-das16jr/16", + .ai_maxdata = 0xffff, + .ai_speed = 10000, + .ai_pg = das16_pg_16jr_16, + .size = 0x10, + .id = 0x00, + }, { + .name = "das-1201", + .ai_maxdata = 0x0fff, + .ai_speed = 20000, + .ai_pg = das16_pg_none, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0x20, + }, { + .name = "das-1202", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_none, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0x20, + }, { + .name = "das-1401", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1601, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1402", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1601", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1601, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "das-1602", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1401/12", + .ai_maxdata = 0x0fff, + .ai_speed = 6250, + .ai_pg = das16_pg_1601, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1402/12", + .ai_maxdata = 0x0fff, + .ai_speed = 6250, + .ai_pg = das16_pg_1602, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1402/16", + .ai_maxdata = 0xffff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1601/12", + .ai_maxdata = 0x0fff, + .ai_speed = 6250, + .ai_pg = das16_pg_1601, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1602/12", + .ai_maxdata = 0x0fff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das1602/16", + .ai_maxdata = 0xffff, + .ai_speed = 10000, + .ai_pg = das16_pg_1602, + .has_ao = 1, + .has_8255 = 1, + .i8255_offset = 0x400, + .size = 0x408, + .id = 0xc0, + }, { + .name = "cio-das16/330", + .ai_maxdata = 0x0fff, + .ai_speed = 3030, + .ai_pg = das16_pg_16jr, + .size = 0x14, + .id = 0xf0, + }, }; -#define DAS16_TIMEOUT 1000 - /* Period for timer interrupt in jiffies. It's a function * to deal with possibility of dynamic HZ patches */ static inline int timer_period(void) @@ -737,256 +451,354 @@ static inline int timer_period(void) } struct das16_private_struct { - unsigned int ai_unipolar; /* unipolar flag */ - unsigned int ai_singleended; /* single ended flag */ - unsigned int clockbase; /* master clock speed in ns */ - volatile unsigned int control_state; /* dma, interrupt and trigger control bits */ - volatile unsigned long adc_byte_count; /* number of bytes remaining */ - /* divisor dividing master clock to get conversion frequency */ - unsigned int divisor1; - /* divisor dividing master clock to get conversion frequency */ - unsigned int divisor2; - unsigned int dma_chan; /* dma channel */ - uint16_t *dma_buffer[2]; - dma_addr_t dma_buffer_addr[2]; - unsigned int current_buffer; - volatile unsigned int dma_transfer_size; /* target number of bytes to transfer per dma shot */ - /** - * user-defined analog input and output ranges - * defined from config options - */ - struct comedi_lrange *user_ai_range_table; - struct comedi_lrange *user_ao_range_table; - - struct timer_list timer; /* for timed interrupt */ - volatile short timer_running; - volatile short timer_mode; /* true if using timer mode */ + unsigned int clockbase; + unsigned int ctrl_reg; + unsigned long adc_byte_count; + unsigned int divisor1; + unsigned int divisor2; + unsigned int dma_chan; + uint16_t *dma_buffer[2]; + dma_addr_t dma_buffer_addr[2]; + unsigned int current_buffer; + unsigned int dma_transfer_size; + struct comedi_lrange *user_ai_range_table; + struct comedi_lrange *user_ao_range_table; + struct timer_list timer; + short timer_running; + unsigned long extra_iobase; + unsigned int can_burst:1; }; -#define devpriv ((struct das16_private_struct *)(dev->private)) -#define thisboard ((struct das16_board *)(dev->board_ptr)) + +static void das16_ai_enable(struct comedi_device *dev, + unsigned int mode, unsigned int src) +{ + struct das16_private_struct *devpriv = dev->private; + + devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | + DAS16_CTRL_DMAE | + DAS16_CTRL_PACING_MASK); + devpriv->ctrl_reg |= mode; + + if (src == TRIG_EXT) + devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER; + else + devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER; + outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); +} + +static void das16_ai_disable(struct comedi_device *dev) +{ + struct das16_private_struct *devpriv = dev->private; + + /* disable interrupts, dma and pacer clocked conversions */ + devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | + DAS16_CTRL_DMAE | + DAS16_CTRL_PACING_MASK); + outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); +} + +/* the pc104-das16jr (at least) has problems if the dma + transfer is interrupted in the middle of transferring + a 16 bit sample, so this function takes care to get + an even transfer count after disabling dma + channel. +*/ +static int disable_dma_on_even(struct comedi_device *dev) +{ + struct das16_private_struct *devpriv = dev->private; + int residue; + int i; + static const int disable_limit = 100; + static const int enable_timeout = 100; + + disable_dma(devpriv->dma_chan); + residue = get_dma_residue(devpriv->dma_chan); + for (i = 0; i < disable_limit && (residue % 2); ++i) { + int j; + enable_dma(devpriv->dma_chan); + for (j = 0; j < enable_timeout; ++j) { + int new_residue; + udelay(2); + new_residue = get_dma_residue(devpriv->dma_chan); + if (new_residue != residue) + break; + } + disable_dma(devpriv->dma_chan); + residue = get_dma_residue(devpriv->dma_chan); + } + if (i == disable_limit) { + dev_err(dev->class_dev, + "failed to get an even dma transfer, could be trouble\n"); + } + return residue; +} + +static void das16_interrupt(struct comedi_device *dev) +{ + struct das16_private_struct *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned long spin_flags; + unsigned long dma_flags; + int num_bytes, residue; + int buffer_index; + + spin_lock_irqsave(&dev->spinlock, spin_flags); + if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) { + spin_unlock_irqrestore(&dev->spinlock, spin_flags); + return; + } + + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma_chan); + residue = disable_dma_on_even(dev); + + /* figure out how many points to read */ + if (residue > devpriv->dma_transfer_size) { + dev_err(dev->class_dev, "residue > transfer size!\n"); + async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + num_bytes = 0; + } else + num_bytes = devpriv->dma_transfer_size - residue; + + if (cmd->stop_src == TRIG_COUNT && + num_bytes >= devpriv->adc_byte_count) { + num_bytes = devpriv->adc_byte_count; + async->events |= COMEDI_CB_EOA; + } + + buffer_index = devpriv->current_buffer; + devpriv->current_buffer = (devpriv->current_buffer + 1) % 2; + devpriv->adc_byte_count -= num_bytes; + + /* re-enable dma */ + if ((async->events & COMEDI_CB_EOA) == 0) { + set_dma_addr(devpriv->dma_chan, + devpriv->dma_buffer_addr[devpriv->current_buffer]); + set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); + enable_dma(devpriv->dma_chan); + } + release_dma_lock(dma_flags); + + spin_unlock_irqrestore(&dev->spinlock, spin_flags); + + cfc_write_array_to_buffer(s, + devpriv->dma_buffer[buffer_index], num_bytes); + + cfc_handle_events(dev, s); +} + +static void das16_timer_interrupt(unsigned long arg) +{ + struct comedi_device *dev = (struct comedi_device *)arg; + struct das16_private_struct *devpriv = dev->private; + + das16_interrupt(dev); + + if (devpriv->timer_running) + mod_timer(&devpriv->timer, jiffies + timer_period()); +} + +static int das16_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; + + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != ((chan0 + i) % s->n_chan)) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } + + return 0; +} static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp; - int gain, start_chan, i; - int mask; - - /* make sure triggers are valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - mask = TRIG_FOLLOW; - /* if board supports burst mode */ - if (thisboard->size > 0x400) - mask |= TRIG_TIMER | TRIG_EXT; - cmd->scan_begin_src &= mask; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - mask = TRIG_TIMER | TRIG_EXT; - /* if board supports burst mode */ - if (thisboard->size > 0x400) - mask |= TRIG_NOW; - cmd->convert_src &= mask; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + const struct das16_board *board = comedi_board(dev); + struct das16_private_struct *devpriv = dev->private; + int err = 0; + unsigned int trig_mask; + unsigned int arg; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + + trig_mask = TRIG_FOLLOW; + if (devpriv->can_burst) + trig_mask |= TRIG_TIMER | TRIG_EXT; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, trig_mask); + + trig_mask = TRIG_TIMER | TRIG_EXT; + if (devpriv->can_burst) + trig_mask |= TRIG_NOW; + err |= cfc_check_trigger_src(&cmd->convert_src, trig_mask); + + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /** - * step 2: make sure trigger sources are unique and - * mutually compatible - */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* 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 */ /* make sure scan_begin_src and convert_src dont conflict */ if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) - err++; + err |= -EINVAL; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) - err++; + err |= -EINVAL; if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + /* Step 3: check if arguments are trivially valid */ - if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* internal trigger */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - /* check against maximum frequency */ - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < - thisboard->ai_speed * cmd->chanlist_len) { - cmd->scan_begin_arg = - thisboard->ai_speed * cmd->chanlist_len; - err++; - } - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < thisboard->ai_speed) { - cmd->convert_arg = thisboard->ai_speed; - err++; - } - } + if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */ + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + + /* check against maximum frequency */ + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + board->ai_speed * cmd->chanlist_len); + + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + board->ai_speed); + + if (cmd->stop_src == TRIG_NONE) + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); - if (cmd->stop_src == TRIG_NONE) { - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } if (err) return 3; /* step 4: fix up arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - unsigned int tmp = cmd->scan_begin_arg; - /* set divisors, correct timing arguments */ - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->scan_begin_arg), - cmd->flags & TRIG_ROUND_MASK); - err += (tmp != cmd->scan_begin_arg); + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - unsigned int tmp = cmd->convert_arg; - /* set divisors, correct timing arguments */ - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); - err += (tmp != cmd->convert_arg); + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - comedi_error(dev, - "entries in chanlist must be " - "consecutive channels, " - "counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all " - "have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das16_ai_check_chanlist(dev, s, cmd); + if (err) return 5; return 0; } +static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, + int rounding_flags) +{ + struct das16_private_struct *devpriv = dev->private; + unsigned long timer_base = dev->iobase + DAS16_TIMER_BASE_REG; + + i8253_cascade_ns_to_timer(devpriv->clockbase, + &devpriv->divisor1, &devpriv->divisor2, + &ns, rounding_flags); + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); + + return ns; +} + static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct das16_board *board = comedi_board(dev); + struct das16_private_struct *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int byte; unsigned long flags; int range; - if (devpriv->dma_chan == 0 || (dev->irq == 0 - && devpriv->timer_mode == 0)) { - comedi_error(dev, - "irq (or use of 'timer mode') dma required to " - "execute comedi_cmd"); - return -1; - } if (cmd->flags & TRIG_RT) { - comedi_error(dev, "isa dma transfers cannot be performed with " - "TRIG_RT, aborting"); + dev_err(dev->class_dev, + "isa dma transfers cannot be performed with TRIG_RT, aborting\n"); return -1; } - devpriv->adc_byte_count = - cmd->stop_arg * cmd->chanlist_len * sizeof(uint16_t); + devpriv->adc_byte_count = cmd->stop_arg * cfc_bytes_per_scan(s); - /* disable conversions for das1600 mode */ - if (thisboard->size > 0x400) - outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV); + if (devpriv->can_burst) + outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG); /* set scan limits */ byte = CR_CHAN(cmd->chanlist[0]); byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4; - outb(byte, dev->iobase + DAS16_MUX); + outb(byte, dev->iobase + DAS16_MUX_REG); /* set gain (this is also burst rate register but according to * computer boards manual, burst rate does nothing, even on * keithley cards) */ - if (thisboard->ai_pg != das16_pg_none) { + if (board->ai_pg != das16_pg_none) { range = CR_RANGE(cmd->chanlist[0]); - outb((das16_gainlists[thisboard->ai_pg])[range], - dev->iobase + DAS16_GAIN); + outb((das16_gainlists[board->ai_pg])[range], + dev->iobase + DAS16_GAIN_REG); } /* set counter mode and counts */ cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); - DEBUG_PRINT("pacer period: %d ns\n", cmd->convert_arg); /* enable counters */ byte = 0; - /* Enable burst mode if appropriate. */ - if (thisboard->size > 0x400) { + if (devpriv->can_burst) { if (cmd->convert_src == TRIG_NOW) { - outb(DAS1600_BURST_VAL, dev->iobase + DAS1600_BURST); + outb(DAS1600_BURST_VAL, + dev->iobase + DAS1600_BURST_REG); /* set burst length */ - byte |= BURST_LEN_BITS(cmd->chanlist_len - 1); + byte |= DAS16_PACER_BURST_LEN(cmd->chanlist_len - 1); } else { - outb(0, dev->iobase + DAS1600_BURST); + outb(0, dev->iobase + DAS1600_BURST_REG); } } - outb(byte, dev->iobase + DAS16_PACER); + outb(byte, dev->iobase + DAS16_PACER_REG); /* set up dma transfer */ flags = claim_dma_lock(); @@ -997,695 +809,420 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->current_buffer = 0; set_dma_addr(devpriv->dma_chan, devpriv->dma_buffer_addr[devpriv->current_buffer]); - /* set appropriate size of transfer */ - devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, *cmd); + devpriv->dma_transfer_size = DAS16_DMA_SIZE; set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); enable_dma(devpriv->dma_chan); release_dma_lock(flags); /* set up interrupt */ - if (devpriv->timer_mode) { - devpriv->timer_running = 1; - devpriv->timer.expires = jiffies + timer_period(); - add_timer(&devpriv->timer); - devpriv->control_state &= ~DAS16_INTE; - } else { - /* clear interrupt bit */ - outb(0x00, dev->iobase + DAS16_STATUS); - /* enable interrupts */ - devpriv->control_state |= DAS16_INTE; - } - devpriv->control_state |= DMA_ENABLE; - devpriv->control_state &= ~PACING_MASK; - if (cmd->convert_src == TRIG_EXT) - devpriv->control_state |= EXT_PACER; - else - devpriv->control_state |= INT_PACER; - outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); + devpriv->timer_running = 1; + devpriv->timer.expires = jiffies + timer_period(); + add_timer(&devpriv->timer); - /* Enable conversions if using das1600 mode */ - if (thisboard->size > 0x400) - outb(0, dev->iobase + DAS1600_CONV); + das16_ai_enable(dev, DAS16_CTRL_DMAE, cmd->convert_src); + if (devpriv->can_burst) + outb(0, dev->iobase + DAS1600_CONV_REG); return 0; } static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct das16_private_struct *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); - /* disable interrupts, dma and pacer clocked conversions */ - devpriv->control_state &= ~DAS16_INTE & ~PACING_MASK & ~DMA_ENABLE; - outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); - if (devpriv->dma_chan) - disable_dma(devpriv->dma_chan); + + das16_ai_disable(dev); + disable_dma(devpriv->dma_chan); /* disable SW timer */ - if (devpriv->timer_mode && devpriv->timer_running) { + if (devpriv->timer_running) { devpriv->timer_running = 0; del_timer(&devpriv->timer); } - /* disable burst mode */ - if (thisboard->size > 0x400) - outb(0, dev->iobase + DAS1600_BURST); - + if (devpriv->can_burst) + outb(0, dev->iobase + DAS1600_BURST_REG); spin_unlock_irqrestore(&dev->spinlock, flags); return 0; } -static void das16_reset(struct comedi_device *dev) -{ - outb(0, dev->iobase + DAS16_STATUS); - outb(0, dev->iobase + DAS16_CONTROL); - outb(0, dev->iobase + DAS16_PACER); - outb(0, dev->iobase + DAS16_CNTR_CONTROL); -} - -static int das16_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void das16_ai_munge(struct comedi_device *dev, + struct comedi_subdevice *s, void *array, + unsigned int num_bytes, + unsigned int start_chan_index) { - int i, n; - int range; - int chan; - int msb, lsb; - - /* disable interrupts and pacing */ - devpriv->control_state &= ~DAS16_INTE & ~DMA_ENABLE & ~PACING_MASK; - outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); - - /* set multiplexer */ - chan = CR_CHAN(insn->chanspec); - chan |= CR_CHAN(insn->chanspec) << 4; - outb(chan, dev->iobase + DAS16_MUX); - - /* set gain */ - if (thisboard->ai_pg != das16_pg_none) { - range = CR_RANGE(insn->chanspec); - outb((das16_gainlists[thisboard->ai_pg])[range], - dev->iobase + DAS16_GAIN); - } - - for (n = 0; n < insn->n; n++) { - /* trigger conversion */ - outb_p(0, dev->iobase + DAS16_TRIG); - - for (i = 0; i < DAS16_TIMEOUT; i++) { - if (!(inb(dev->iobase + DAS16_STATUS) & BUSY)) - break; - } - if (i == DAS16_TIMEOUT) { - printk("das16: timeout\n"); - return -ETIME; - } - msb = inb(dev->iobase + DAS16_AI_MSB); - lsb = inb(dev->iobase + DAS16_AI_LSB); - if (thisboard->ai_nbits == 12) - data[n] = ((lsb >> 4) & 0xf) | (msb << 4); - else - data[n] = lsb | (msb << 8); + unsigned int i, num_samples = num_bytes / sizeof(short); + unsigned short *data = array; + for (i = 0; i < num_samples; i++) { + data[i] = le16_to_cpu(data[i]); + if (s->maxdata == 0x0fff) + data[i] >>= 4; + data[i] &= s->maxdata; } - - return n; -} - -static int das16_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int bits; - - bits = inb(dev->iobase + DAS16_DIO) & 0xf; - data[1] = bits; - data[0] = 0; - - return 2; } -static int das16_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das16_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned int wbits; - - /* only set bits that have been masked */ - data[0] &= 0xf; - wbits = s->state; - /* zero bits that have been masked */ - wbits &= ~data[0]; - /* set masked bits */ - wbits |= data[0] & data[1]; - s->state = wbits; - data[1] = wbits; + unsigned int status; - outb(s->state, dev->iobase + DAS16_DIO); - - return 2; + status = inb(dev->iobase + DAS16_STATUS_REG); + if ((status & DAS16_STATUS_BUSY) == 0) + return 0; + return -EBUSY; } -static int das16_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das16_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + const struct das16_board *board = comedi_board(dev); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int ret; int i; - int lsb, msb; - int chan; - chan = CR_CHAN(insn->chanspec); + das16_ai_disable(dev); - for (i = 0; i < insn->n; i++) { - if (thisboard->ao_nbits == 12) { - lsb = (data[i] << 4) & 0xff; - msb = (data[i] >> 4) & 0xff; - } else { - lsb = data[i] & 0xff; - msb = (data[i] >> 8) & 0xff; - } - outb(lsb, dev->iobase + DAS16_AO_LSB(chan)); - outb(msb, dev->iobase + DAS16_AO_MSB(chan)); + /* set multiplexer */ + outb(chan | (chan << 4), dev->iobase + DAS16_MUX_REG); + + /* set gain */ + if (board->ai_pg != das16_pg_none) { + outb((das16_gainlists[board->ai_pg])[range], + dev->iobase + DAS16_GAIN_REG); } - return i; -} + for (i = 0; i < insn->n; i++) { + /* trigger conversion */ + outb_p(0, dev->iobase + DAS16_TRIG_REG); -static irqreturn_t das16_dma_interrupt(int irq, void *d) -{ - int status; - struct comedi_device *dev = d; + ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0); + if (ret) + return ret; - status = inb(dev->iobase + DAS16_STATUS); + val = inb(dev->iobase + DAS16_AI_MSB_REG) << 8; + val |= inb(dev->iobase + DAS16_AI_LSB_REG); + if (s->maxdata == 0x0fff) + val >>= 4; + val &= s->maxdata; - if ((status & DAS16_INT) == 0) { - DEBUG_PRINT("spurious interrupt\n"); - return IRQ_NONE; + data[i] = val; } - /* clear interrupt */ - outb(0x00, dev->iobase + DAS16_STATUS); - das16_interrupt(dev); - return IRQ_HANDLED; -} - -static void das16_timer_interrupt(unsigned long arg) -{ - struct comedi_device *dev = (struct comedi_device *)arg; - - das16_interrupt(dev); - - if (devpriv->timer_running) - mod_timer(&devpriv->timer, jiffies + timer_period()); + return insn->n; } -/* the pc104-das16jr (at least) has problems if the dma - transfer is interrupted in the middle of transferring - a 16 bit sample, so this function takes care to get - an even transfer count after disabling dma - channel. -*/ -static int disable_dma_on_even(struct comedi_device *dev) +static int das16_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int residue; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; int i; - static const int disable_limit = 100; - static const int enable_timeout = 100; - disable_dma(devpriv->dma_chan); - residue = get_dma_residue(devpriv->dma_chan); - for (i = 0; i < disable_limit && (residue % 2); ++i) { - int j; - enable_dma(devpriv->dma_chan); - for (j = 0; j < enable_timeout; ++j) { - int new_residue; - udelay(2); - new_residue = get_dma_residue(devpriv->dma_chan); - if (new_residue != residue) - break; - } - disable_dma(devpriv->dma_chan); - residue = get_dma_residue(devpriv->dma_chan); - } - if (i == disable_limit) { - comedi_error(dev, "failed to get an even dma transfer, " - "could be trouble."); - } - return residue; -} - -static void das16_interrupt(struct comedi_device *dev) -{ - unsigned long dma_flags, spin_flags; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async; - struct comedi_cmd *cmd; - int num_bytes, residue; - int buffer_index; - - if (dev->attached == 0) { - comedi_error(dev, "premature interrupt"); - return; - } - /* initialize async here to make sure it is not NULL */ - async = s->async; - cmd = &async->cmd; - - if (devpriv->dma_chan == 0) { - comedi_error(dev, "interrupt with no dma channel?"); - return; - } - - spin_lock_irqsave(&dev->spinlock, spin_flags); - if ((devpriv->control_state & DMA_ENABLE) == 0) { - spin_unlock_irqrestore(&dev->spinlock, spin_flags); - DEBUG_PRINT("interrupt while dma disabled?\n"); - return; - } - - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma_chan); - residue = disable_dma_on_even(dev); - - /* figure out how many points to read */ - if (residue > devpriv->dma_transfer_size) { - comedi_error(dev, "residue > transfer size!\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - num_bytes = 0; - } else - num_bytes = devpriv->dma_transfer_size - residue; - - if (cmd->stop_src == TRIG_COUNT && - num_bytes >= devpriv->adc_byte_count) { - num_bytes = devpriv->adc_byte_count; - async->events |= COMEDI_CB_EOA; - } - - buffer_index = devpriv->current_buffer; - devpriv->current_buffer = (devpriv->current_buffer + 1) % 2; - devpriv->adc_byte_count -= num_bytes; - - /* figure out how many bytes for next transfer */ - if (cmd->stop_src == TRIG_COUNT && devpriv->timer_mode == 0 && - devpriv->dma_transfer_size > devpriv->adc_byte_count) - devpriv->dma_transfer_size = devpriv->adc_byte_count; - /* re-enable dma */ - if ((async->events & COMEDI_CB_EOA) == 0) { - set_dma_addr(devpriv->dma_chan, - devpriv->dma_buffer_addr[devpriv->current_buffer]); - set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_chan); - /* reenable conversions for das1600 mode, (stupid hardware) */ - if (thisboard->size > 0x400 && devpriv->timer_mode == 0) - outb(0x00, dev->iobase + DAS1600_CONV); + for (i = 0; i < insn->n; i++) { + val = data[i]; + val <<= 4; + outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + DAS16_AO_MSB_REG(chan)); } - release_dma_lock(dma_flags); - spin_unlock_irqrestore(&dev->spinlock, spin_flags); - - cfc_write_array_to_buffer(s, - devpriv->dma_buffer[buffer_index], num_bytes); - - cfc_handle_events(dev, s); + return insn->n; } -static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns, - int rounding_flags) +static int das16_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - i8253_cascade_ns_to_timer_2div(devpriv->clockbase, &(devpriv->divisor1), - &(devpriv->divisor2), &ns, - rounding_flags & TRIG_ROUND_MASK); - - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 1, devpriv->divisor1, 2); - i8254_load(dev->iobase + DAS16_CNTR0_DATA, 0, 2, devpriv->divisor2, 2); + data[1] = inb(dev->iobase + DAS16_DIO_REG) & 0xf; - return ns; + return insn->n; } -static void reg_dump(struct comedi_device *dev) +static int das16_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - DEBUG_PRINT("********DAS1600 REGISTER DUMP********\n"); - DEBUG_PRINT("DAS16_MUX: %x\n", inb(dev->iobase + DAS16_MUX)); - DEBUG_PRINT("DAS16_DIO: %x\n", inb(dev->iobase + DAS16_DIO)); - DEBUG_PRINT("DAS16_STATUS: %x\n", inb(dev->iobase + DAS16_STATUS)); - DEBUG_PRINT("DAS16_CONTROL: %x\n", inb(dev->iobase + DAS16_CONTROL)); - DEBUG_PRINT("DAS16_PACER: %x\n", inb(dev->iobase + DAS16_PACER)); - DEBUG_PRINT("DAS16_GAIN: %x\n", inb(dev->iobase + DAS16_GAIN)); - DEBUG_PRINT("DAS16_CNTR_CONTROL: %x\n", - inb(dev->iobase + DAS16_CNTR_CONTROL)); - DEBUG_PRINT("DAS1600_CONV: %x\n", inb(dev->iobase + DAS1600_CONV)); - DEBUG_PRINT("DAS1600_BURST: %x\n", inb(dev->iobase + DAS1600_BURST)); - DEBUG_PRINT("DAS1600_ENABLE: %x\n", inb(dev->iobase + DAS1600_ENABLE)); - DEBUG_PRINT("DAS1600_STATUS_B: %x\n", - inb(dev->iobase + DAS1600_STATUS_B)); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS16_DIO_REG); + + data[1] = s->state; + + return insn->n; } static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it) { - int status; + const struct das16_board *board = comedi_board(dev); int diobits; - /* status is available on all boards */ - - status = inb(dev->iobase + DAS16_STATUS); - - if ((status & UNIPOLAR)) - devpriv->ai_unipolar = 1; - else - devpriv->ai_unipolar = 0; - - - if ((status & DAS16_MUXBIT)) - devpriv->ai_singleended = 1; - else - devpriv->ai_singleended = 0; - - /* diobits indicates boards */ - - diobits = inb(dev->iobase + DAS16_DIO) & 0xf0; - - printk(KERN_INFO " id bits are 0x%02x\n", diobits); - if (thisboard->id != diobits) { - printk(KERN_INFO " requested board's id bits are 0x%x (ignore)\n", - thisboard->id); + diobits = inb(dev->iobase + DAS16_DIO_REG) & 0xf0; + if (board->id != diobits) { + dev_err(dev->class_dev, + "requested board's id bits are incorrect (0x%x != 0x%x)\n", + board->id, diobits); + return -EINVAL; } return 0; } -static int das1600_mode_detect(struct comedi_device *dev) +static void das16_reset(struct comedi_device *dev) { - int status = 0; - - status = inb(dev->iobase + DAS1600_STATUS_B); - - if (status & DAS1600_CLK_10MHZ) { - devpriv->clockbase = 100; - printk(KERN_INFO " 10MHz pacer clock\n"); - } else { - devpriv->clockbase = 1000; - printk(KERN_INFO " 1MHz pacer clock\n"); - } - - reg_dump(dev); - - return 0; + outb(0, dev->iobase + DAS16_STATUS_REG); + outb(0, dev->iobase + DAS16_CTRL_REG); + outb(0, dev->iobase + DAS16_PACER_REG); + outb(0, dev->iobase + DAS16_TIMER_BASE_REG + i8254_control_reg); } -/* - * - * Options list: - * 0 I/O base - * 1 IRQ - * 2 DMA - * 3 Clock speed (in MHz) - */ - static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct das16_board *board = comedi_board(dev); + struct das16_private_struct *devpriv; struct comedi_subdevice *s; + struct comedi_lrange *lrange; + struct comedi_krange *krange; + unsigned int dma_chan = it->options[2]; + unsigned int status; int ret; - unsigned int irq; - unsigned long iobase; - unsigned int dma_chan; - int timer_mode; - unsigned long flags; - struct comedi_krange *user_ai_range, *user_ao_range; - - iobase = it->options[0]; -#if 0 - irq = it->options[1]; - timer_mode = it->options[8]; -#endif - /* always use time_mode since using irq can drop samples while - * waiting for dma done interrupt (due to hardware limitations) */ - irq = 0; - timer_mode = 1; - if (timer_mode) - irq = 0; - - printk(KERN_INFO "comedi%d: das16:", dev->minor); /* check that clock setting is valid */ if (it->options[3]) { if (it->options[3] != 0 && it->options[3] != 1 && it->options[3] != 10) { - printk - ("\n Invalid option. Master clock must be set " - "to 1 or 10 (MHz)\n"); + dev_err(dev->class_dev, + "Invalid option. Master clock must be set to 1 or 10 (MHz)\n"); return -EINVAL; } } - ret = alloc_private(dev, sizeof(struct das16_private_struct)); - if (ret < 0) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - if (thisboard->size < 0x400) { - printk(" 0x%04lx-0x%04lx\n", iobase, iobase + thisboard->size); - if (!request_region(iobase, thisboard->size, "das16")) { - printk(KERN_ERR " I/O port conflict\n"); - return -EIO; - } + if (board->size < 0x400) { + ret = comedi_request_region(dev, it->options[0], board->size); + if (ret) + return ret; } else { - printk(KERN_INFO " 0x%04lx-0x%04lx 0x%04lx-0x%04lx\n", - iobase, iobase + 0x0f, - iobase + 0x400, - iobase + 0x400 + (thisboard->size & 0x3ff)); - if (!request_region(iobase, 0x10, "das16")) { - printk(KERN_ERR " I/O port conflict: 0x%04lx-0x%04lx\n", - iobase, iobase + 0x0f); - return -EIO; - } - if (!request_region(iobase + 0x400, thisboard->size & 0x3ff, - "das16")) { - release_region(iobase, 0x10); - printk(KERN_ERR " I/O port conflict: 0x%04lx-0x%04lx\n", - iobase + 0x400, - iobase + 0x400 + (thisboard->size & 0x3ff)); - return -EIO; - } + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; + /* Request an additional region for the 8255 */ + ret = __comedi_request_region(dev, dev->iobase + 0x400, + board->size & 0x3ff); + if (ret) + return ret; + devpriv->extra_iobase = dev->iobase + 0x400; + devpriv->can_burst = 1; } - dev->iobase = iobase; - /* probe id bits to make sure they are consistent */ - if (das16_probe(dev, it)) { - printk(KERN_ERR " id bits do not match selected board, aborting\n"); + if (das16_probe(dev, it)) return -EINVAL; - } - dev->board_name = thisboard->name; /* get master clock speed */ - if (thisboard->size < 0x400) { - if (it->options[3]) - devpriv->clockbase = 1000 / it->options[3]; - else - devpriv->clockbase = 1000; /* 1 MHz default */ - } else { - das1600_mode_detect(dev); - } + if (devpriv->can_burst) { + status = inb(dev->iobase + DAS1600_STATUS_REG); - /* now for the irq */ - if (irq > 1 && irq < 8) { - ret = request_irq(irq, das16_dma_interrupt, 0, "das16", dev); - - if (ret < 0) - return ret; - dev->irq = irq; - printk(KERN_INFO " ( irq = %u )", irq); - } else if (irq == 0) { - printk(" ( no irq )"); + if (status & DAS1600_STATUS_CLK_10MHZ) + devpriv->clockbase = I8254_OSC_BASE_10MHZ; + else + devpriv->clockbase = I8254_OSC_BASE_1MHZ; } else { - printk(" invalid irq\n"); - return -EINVAL; + if (it->options[3]) + devpriv->clockbase = I8254_OSC_BASE_1MHZ / + it->options[3]; + else + devpriv->clockbase = I8254_OSC_BASE_1MHZ; } - /* initialize dma */ - dma_chan = it->options[2]; + /* initialize dma */ if (dma_chan == 1 || dma_chan == 3) { - /* allocate dma buffers */ + unsigned long flags; int i; - for (i = 0; i < 2; i++) { - devpriv->dma_buffer[i] = pci_alloc_consistent( - NULL, DAS16_DMA_SIZE, - &devpriv->dma_buffer_addr[i]); - if (devpriv->dma_buffer[i] == NULL) - return -ENOMEM; - } - if (request_dma(dma_chan, "das16")) { - printk(KERN_ERR " failed to allocate dma channel %i\n", - dma_chan); + if (request_dma(dma_chan, dev->board_name)) { + dev_err(dev->class_dev, + "failed to request dma channel %i\n", + dma_chan); return -EINVAL; } devpriv->dma_chan = dma_chan; + + /* allocate dma buffers */ + for (i = 0; i < 2; i++) { + void *p; + + p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE, + &devpriv->dma_buffer_addr[i]); + if (!p) + return -ENOMEM; + devpriv->dma_buffer[i] = p; + } + flags = claim_dma_lock(); disable_dma(devpriv->dma_chan); set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); release_dma_lock(flags); - printk(KERN_INFO " ( dma = %u)\n", dma_chan); - } else if (dma_chan == 0) { - printk(KERN_INFO " ( no dma )\n"); - } else { - printk(KERN_ERR " invalid dma channel\n"); - return -EINVAL; + + init_timer(&devpriv->timer); + devpriv->timer.function = das16_timer_interrupt; + devpriv->timer.data = (unsigned long)dev; } - /* get any user-defined input range */ - if (thisboard->ai_pg == das16_pg_none && + /* get any user-defined input range */ + if (board->ai_pg == das16_pg_none && (it->options[4] || it->options[5])) { - /* allocate single-range range table */ - devpriv->user_ai_range_table = - kmalloc(sizeof(struct comedi_lrange) + - sizeof(struct comedi_krange), GFP_KERNEL); - /* initialize ai range */ - devpriv->user_ai_range_table->length = 1; - user_ai_range = devpriv->user_ai_range_table->range; - user_ai_range->min = it->options[4]; - user_ai_range->max = it->options[5]; - user_ai_range->flags = UNIT_volt; - } - /* get any user-defined output range */ - if (it->options[6] || it->options[7]) { - /* allocate single-range range table */ - devpriv->user_ao_range_table = - kmalloc(sizeof(struct comedi_lrange) + - sizeof(struct comedi_krange), GFP_KERNEL); - /* initialize ao range */ - devpriv->user_ao_range_table->length = 1; - user_ao_range = devpriv->user_ao_range_table->range; - user_ao_range->min = it->options[6]; - user_ao_range->max = it->options[7]; - user_ao_range->flags = UNIT_volt; + /* allocate single-range range table */ + lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL); + if (!lrange) + return -ENOMEM; + + /* initialize ai range */ + devpriv->user_ai_range_table = lrange; + lrange->length = 1; + krange = devpriv->user_ai_range_table->range; + krange->min = it->options[4]; + krange->max = it->options[5]; + krange->flags = UNIT_volt; } - if (timer_mode) { - init_timer(&(devpriv->timer)); - devpriv->timer.function = das16_timer_interrupt; - devpriv->timer.data = (unsigned long)dev; + /* get any user-defined output range */ + if (it->options[6] || it->options[7]) { + /* allocate single-range range table */ + lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL); + if (!lrange) + return -ENOMEM; + + /* initialize ao range */ + devpriv->user_ao_range_table = lrange; + lrange->length = 1; + krange = devpriv->user_ao_range_table->range; + krange->min = it->options[6]; + krange->max = it->options[7]; + krange->flags = UNIT_volt; } - devpriv->timer_mode = timer_mode ? 1 : 0; - ret = alloc_subdevices(dev, 5); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4 + board->has_8255); + if (ret) return ret; - s = dev->subdevices + 0; - dev->read_subdev = s; - /* ai */ - if (thisboard->ai) { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - if (devpriv->ai_singleended) { - s->n_chan = 16; - s->len_chanlist = 16; - s->subdev_flags |= SDF_GROUND; - } else { - s->n_chan = 8; - s->len_chanlist = 8; - s->subdev_flags |= SDF_DIFF; - } - s->maxdata = (1 << thisboard->ai_nbits) - 1; - if (devpriv->user_ai_range_table) { /* user defined ai range */ - s->range_table = devpriv->user_ai_range_table; - } else if (devpriv->ai_unipolar) { - s->range_table = das16_ai_uni_lranges[thisboard->ai_pg]; - } else { - s->range_table = das16_ai_bip_lranges[thisboard->ai_pg]; - } - s->insn_read = thisboard->ai; - s->do_cmdtest = das16_cmd_test; - s->do_cmd = das16_cmd_exec; - s->cancel = das16_cancel; - s->munge = das16_ai_munge; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - s = dev->subdevices + 1; - /* ao */ - if (thisboard->ao) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; - s->maxdata = (1 << thisboard->ao_nbits) - 1; - /* user defined ao range */ - if (devpriv->user_ao_range_table) - s->range_table = devpriv->user_ao_range_table; - else - s->range_table = &range_unknown; + status = inb(dev->iobase + DAS16_STATUS_REG); - s->insn_write = thisboard->ao; + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (status & DAS16_STATUS_MUXBIT) { + s->subdev_flags |= SDF_GROUND; + s->n_chan = 16; } else { - s->type = COMEDI_SUBD_UNUSED; + s->subdev_flags |= SDF_DIFF; + s->n_chan = 8; } - - s = dev->subdevices + 2; - /* di */ - if (thisboard->di) { - 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 = thisboard->di; + s->len_chanlist = s->n_chan; + s->maxdata = board->ai_maxdata; + if (devpriv->user_ai_range_table) { /* user defined ai range */ + s->range_table = devpriv->user_ai_range_table; + } else if (status & DAS16_STATUS_UNIPOLAR) { + s->range_table = das16_ai_uni_lranges[board->ai_pg]; } else { - s->type = COMEDI_SUBD_UNUSED; + s->range_table = das16_ai_bip_lranges[board->ai_pg]; + } + s->insn_read = das16_ai_insn_read; + if (devpriv->dma_chan) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->do_cmdtest = das16_cmd_test; + s->do_cmd = das16_cmd_exec; + s->cancel = das16_cancel; + s->munge = das16_ai_munge; } - s = dev->subdevices + 3; - /* do */ - if (thisboard->do_) { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = thisboard->do_; - /* initialize digital output lines */ - outb(s->state, dev->iobase + DAS16_DIO); + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + if (board->has_ao) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = devpriv->user_ao_range_table; + s->insn_write = das16_ao_insn_write; } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 4; - /* 8255 */ - if (thisboard->i8255_offset != 0) { - subdev_8255_init(dev, s, NULL, (dev->iobase + - thisboard->i8255_offset)); - } else { - s->type = COMEDI_SUBD_UNUSED; + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das16_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + 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 = das16_do_insn_bits; + + /* initialize digital output lines */ + outb(s->state, dev->iobase + DAS16_DIO_REG); + + /* 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); + if (ret) + return ret; } das16_reset(dev); /* set the interrupt level */ - devpriv->control_state = DAS16_IRQ(dev->irq); - outb(devpriv->control_state, dev->iobase + DAS16_CONTROL); - - /* turn on das1600 mode if available */ - if (thisboard->size > 0x400) { - outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE); - outb(0, dev->iobase + DAS1600_CONV); - outb(0, dev->iobase + DAS1600_BURST); + devpriv->ctrl_reg = DAS16_CTRL_IRQ(dev->irq); + outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG); + + if (devpriv->can_burst) { + outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE_REG); + outb(0, dev->iobase + DAS1600_CONV_REG); + outb(0, dev->iobase + DAS1600_BURST_REG); } return 0; } -static int das16_detach(struct comedi_device *dev) +static void das16_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: das16: remove\n", dev->minor); - - das16_reset(dev); - - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 4); + const struct das16_board *board = comedi_board(dev); + struct das16_private_struct *devpriv = dev->private; + int i; if (devpriv) { - int i; + if (dev->iobase) + das16_reset(dev); + for (i = 0; i < 2; i++) { if (devpriv->dma_buffer[i]) pci_free_consistent(NULL, DAS16_DMA_SIZE, @@ -1697,95 +1234,26 @@ static int das16_detach(struct comedi_device *dev) free_dma(devpriv->dma_chan); kfree(devpriv->user_ai_range_table); kfree(devpriv->user_ao_range_table); - } - - if (dev->irq) - free_irq(dev->irq, dev); - - if (dev->iobase) { - if (thisboard->size < 0x400) { - release_region(dev->iobase, thisboard->size); - } else { - release_region(dev->iobase, 0x10); - release_region(dev->iobase + 0x400, - thisboard->size & 0x3ff); - } - } - - return 0; -} - -static int __init driver_das16_init_module(void) -{ - return comedi_driver_register(&driver_das16); -} - -static void __exit driver_das16_cleanup_module(void) -{ - comedi_driver_unregister(&driver_das16); -} - -module_init(driver_das16_init_module); -module_exit(driver_das16_cleanup_module); - -/* utility function that suggests a dma transfer size in bytes */ -static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, - struct comedi_cmd cmd) -{ - unsigned int size; - unsigned int freq; - - /* if we are using timer interrupt, we don't care how long it - * will take to complete transfer since it will be interrupted - * by timer interrupt */ - if (devpriv->timer_mode) - return DAS16_DMA_SIZE; - - /* otherwise, we are relying on dma terminal count interrupt, - * so pick a reasonable size */ - if (cmd.convert_src == TRIG_TIMER) - freq = 1000000000 / cmd.convert_arg; - else if (cmd.scan_begin_src == TRIG_TIMER) - freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len; - /* return some default value */ - else - freq = 0xffffffff; - if (cmd.flags & TRIG_WAKE_EOS) { - size = sample_size * cmd.chanlist_len; - } else { - /* make buffer fill in no more than 1/3 second */ - size = (freq / 3) * sample_size; + if (devpriv->extra_iobase) + release_region(devpriv->extra_iobase, + board->size & 0x3ff); } - /* set a minimum and maximum size allowed */ - if (size > DAS16_DMA_SIZE) - size = DAS16_DMA_SIZE - DAS16_DMA_SIZE % sample_size; - else if (size < sample_size) - size = sample_size; - - if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count) - size = devpriv->adc_byte_count; - - return size; + comedi_legacy_detach(dev); } -static void das16_ai_munge(struct comedi_device *dev, - struct comedi_subdevice *s, void *array, - unsigned int num_bytes, - unsigned int start_chan_index) -{ - unsigned int i, num_samples = num_bytes / sizeof(short); - short *data = array; - - for (i = 0; i < num_samples; i++) { - data[i] = le16_to_cpu(data[i]); - if (thisboard->ai_nbits == 12) - data[i] = (data[i] >> 4) & 0xfff; - - } -} +static struct comedi_driver das16_driver = { + .driver_name = "das16", + .module = THIS_MODULE, + .attach = das16_attach, + .detach = das16_detach, + .board_name = &das16_boards[0].name, + .num_names = ARRAY_SIZE(das16_boards), + .offset = sizeof(das16_boards[0]), +}; +module_comedi_driver(das16_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index a5ce3b2abe4..ec039fbff0f 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -17,18 +17,12 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: das16m1 Description: CIO-DAS16/M1 Author: Frank Mori Hess <fmhess@users.sourceforge.net> -Devices: [Measurement Computing] CIO-DAS16/M1 (cio-das16/m1) +Devices: [Measurement Computing] CIO-DAS16/M1 (das16m1) Status: works This driver supports a single board - the CIO-DAS16/M1. @@ -58,7 +52,7 @@ Options: irq can be omitted, although the cmd interface will not work without it. */ -#include <linux/ioport.h> +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" @@ -69,8 +63,6 @@ irq can be omitted, although the cmd interface will not work without it. #define DAS16M1_SIZE 16 #define DAS16M1_SIZE2 8 -#define DAS16M1_XTAL 100 /* 10 MHz master clock */ - #define FIFO_SIZE 1024 /* 1024 sample fifo */ /* @@ -118,69 +110,18 @@ irq can be omitted, although the cmd interface will not work without it. #define DAS16M1_82C55 0x400 #define DAS16M1_8254_THIRD 0x404 -static const struct comedi_lrange range_das16m1 = { 9, - { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10), - } -}; - -static int das16m1_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16m1_di_rbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das16m1_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int das16m1_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int das16m1_cmd_exec(struct comedi_device *dev, - struct comedi_subdevice *s); -static int das16m1_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - -static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t das16m1_interrupt(int irq, void *d); -static void das16m1_handler(struct comedi_device *dev, unsigned int status); - -static unsigned int das16m1_set_pacer(struct comedi_device *dev, - unsigned int ns, int round_flag); - -static int das16m1_irq_bits(unsigned int irq); - -struct das16m1_board { - const char *name; - unsigned int ai_speed; -}; - -static const struct das16m1_board das16m1_boards[] = { - { - .name = "cio-das16/m1", /* CIO-DAS16_M1.pdf */ - .ai_speed = 1000, /* 1MHz max speed */ - }, -}; - -static int das16m1_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int das16m1_detach(struct comedi_device *dev); -static struct comedi_driver driver_das16m1 = { - .driver_name = "das16m1", - .module = THIS_MODULE, - .attach = das16m1_attach, - .detach = das16m1_detach, - .board_name = &das16m1_boards[0].name, - .num_names = ARRAY_SIZE(das16m1_boards), - .offset = sizeof(das16m1_boards[0]), +static const struct comedi_lrange range_das16m1 = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; struct das16m1_private_struct { @@ -190,111 +131,99 @@ struct das16m1_private_struct { * needed to keep track of whether new count has been loaded into * counter yet (loaded by first sample conversion) */ u16 initial_hw_count; - short ai_buffer[FIFO_SIZE]; - unsigned int do_bits; /* saves status of digital output bits */ + unsigned short ai_buffer[FIFO_SIZE]; unsigned int divisor1; /* divides master clock to obtain conversion speed */ unsigned int divisor2; /* divides master clock to obtain conversion speed */ + unsigned long extra_iobase; }; -#define devpriv ((struct das16m1_private_struct *)(dev->private)) -#define thisboard ((const struct das16m1_board *)(dev->board_ptr)) -static int __init driver_das16m1_init_module(void) +static inline unsigned short munge_sample(unsigned short data) { - return comedi_driver_register(&driver_das16m1); + return (data >> 4) & 0xfff; } -static void __exit driver_das16m1_cleanup_module(void) +static void munge_sample_array(unsigned short *array, unsigned int num_elements) { - comedi_driver_unregister(&driver_das16m1); -} + unsigned int i; -module_init(driver_das16m1_init_module); -module_exit(driver_das16m1_cleanup_module); + for (i = 0; i < num_elements; i++) + array[i] = munge_sample(array[i]); +} -static inline short munge_sample(short data) +static int das16m1_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - return (data >> 4) & 0xfff; + int i; + + if (cmd->chanlist_len == 1) + return 0; + + if ((cmd->chanlist_len % 2) != 0) { + dev_dbg(dev->class_dev, + "chanlist must be of even length or length 1\n"); + return -EINVAL; + } + + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + if ((i % 2) != (chan % 2)) { + dev_dbg(dev->class_dev, + "even/odd channels must go have even/odd chanlist indices\n"); + return -EINVAL; + } + } + + return 0; } static int das16m1_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - unsigned int err = 0, tmp, i; - - /* make sure triggers are valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + struct das16m1_private_struct *devpriv = dev->private; + int err = 0; + unsigned int arg; + + /* 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_FOLLOW); + 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 2: make sure trigger sources are unique and mutually compatible */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_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: make sure arguments are trivially compatible */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + /* Step 3: check if arguments are trivially valid */ - if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* internal trigger */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < thisboard->ai_speed) { - cmd->convert_arg = thisboard->ai_speed; - err++; - } - } + if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */ + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 1000); + + 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_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -303,36 +232,20 @@ static int das16m1_cmd_test(struct comedi_device *dev, /* step 4: fix up arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* check chanlist against board's peculiarities */ - if (cmd->chanlist && cmd->chanlist_len > 1) { - for (i = 0; i < cmd->chanlist_len; i++) { - /* even/odd channels must go into even/odd queue addresses */ - if ((i % 2) != (CR_CHAN(cmd->chanlist[i]) % 2)) { - comedi_error(dev, "bad chanlist:\n" - " even/odd channels must go have even/odd chanlist indices"); - err++; - } - } - if ((cmd->chanlist_len % 2) != 0) { - comedi_error(dev, - "chanlist must be of even length or length 1"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das16m1_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -340,18 +253,27 @@ static int das16m1_cmd_test(struct comedi_device *dev, return 0; } +static void das16m1_set_pacer(struct comedi_device *dev) +{ + struct das16m1_private_struct *devpriv = dev->private; + unsigned long timer_base = dev->iobase + DAS16M1_8254_SECOND; + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); +} + static int das16m1_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) { + struct das16m1_private_struct *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned long timer_base = dev->iobase + DAS16M1_8254_FIRST; unsigned int byte, i; - if (dev->irq == 0) { - comedi_error(dev, "irq required to execute comedi_cmd"); - return -1; - } - /* disable interrupts and internal pacer */ devpriv->control_state &= ~INTE & ~PACER_MASK; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); @@ -361,11 +283,11 @@ static int das16m1_cmd_exec(struct comedi_device *dev, /* Initialize lower half of hardware counter, used to determine how * many samples are in fifo. Value doesn't actually load into counter * until counter's next clock (the next a/d conversion) */ - i8254_load(dev->iobase + DAS16M1_8254_FIRST, 0, 1, 0, 2); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, 0); /* remember current reading of counter so we know when counter has * actually been loaded */ - devpriv->initial_hw_count = - i8254_read(dev->iobase + DAS16M1_8254_FIRST, 0, 1); + devpriv->initial_hw_count = i8254_read(timer_base, 0, 1); /* setup channel/gain queue */ for (i = 0; i < cmd->chanlist_len; i++) { outb(i, dev->iobase + DAS16M1_QUEUE_ADDR); @@ -375,29 +297,26 @@ static int das16m1_cmd_exec(struct comedi_device *dev, outb(byte, dev->iobase + DAS16M1_QUEUE_DATA); } - /* set counter mode and counts */ - cmd->convert_arg = - das16m1_set_pacer(dev, cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); + /* enable interrupts and set internal pacer counter mode and counts */ + devpriv->control_state &= ~PACER_MASK; + if (cmd->convert_src == TRIG_TIMER) { + das16m1_set_pacer(dev); + devpriv->control_state |= INT_PACER; + } else { /* TRIG_EXT */ + devpriv->control_state |= EXT_PACER; + } /* set control & status register */ byte = 0; /* if we are using external start trigger (also board dislikes having * both start and conversion triggers external simultaneously) */ - if (cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT) { + if (cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT) byte |= EXT_TRIG_BIT; - } + outb(byte, dev->iobase + DAS16M1_CS); /* clear interrupt bit */ outb(0, dev->iobase + DAS16M1_CLEAR_INTR); - /* enable interrupts and internal pacer */ - devpriv->control_state &= ~PACER_MASK; - if (cmd->convert_src == TRIG_TIMER) { - devpriv->control_state |= INT_PACER; - } else { - devpriv->control_state |= EXT_PACER; - } devpriv->control_state |= INTE; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); @@ -406,19 +325,35 @@ static int das16m1_cmd_exec(struct comedi_device *dev, static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct das16m1_private_struct *devpriv = dev->private; + devpriv->control_state &= ~INTE & ~PACER_MASK; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); return 0; } +static int das16m1_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS16M1_CS); + if (status & IRQDATA) + return 0; + return -EBUSY; +} + static int das16m1_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i, n; + struct das16m1_private_struct *devpriv = dev->private; + int ret; + int n; int byte; - const int timeout = 1000; /* disable interrupts and internal pacer */ devpriv->control_state &= ~INTE & ~PACER_MASK; @@ -436,14 +371,10 @@ static int das16m1_ai_rinsn(struct comedi_device *dev, /* trigger conversion */ outb(0, dev->iobase); - for (i = 0; i < timeout; i++) { - if (inb(dev->iobase + DAS16M1_CS) & IRQDATA) - break; - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0); + if (ret) + return ret; + data[n] = munge_sample(inw(dev->iobase)); } @@ -460,84 +391,25 @@ static int das16m1_di_rbits(struct comedi_device *dev, data[1] = bits; data[0] = 0; - return 2; + return insn->n; } static int das16m1_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int wbits; - - /* only set bits that have been masked */ - data[0] &= 0xf; - wbits = devpriv->do_bits; - /* zero bits that have been masked */ - wbits &= ~data[0]; - /* set masked bits */ - wbits |= data[0] & data[1]; - devpriv->do_bits = wbits; - data[1] = wbits; + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS16M1_DIO); - outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); + data[1] = s->state; - return 2; -} - -static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) -{ - unsigned long flags; - unsigned int status; - - /* prevent race with interrupt handler */ - spin_lock_irqsave(&dev->spinlock, flags); - status = inb(dev->iobase + DAS16M1_CS); - das16m1_handler(dev, status); - spin_unlock_irqrestore(&dev->spinlock, flags); - - return s->async->buf_write_count - s->async->buf_read_count; -} - -static irqreturn_t das16m1_interrupt(int irq, void *d) -{ - int status; - struct comedi_device *dev = d; - - if (dev->attached == 0) { - comedi_error(dev, "premature interrupt"); - return IRQ_HANDLED; - } - /* prevent race with comedi_poll() */ - spin_lock(&dev->spinlock); - - status = inb(dev->iobase + DAS16M1_CS); - - if ((status & (IRQDATA | OVRUN)) == 0) { - comedi_error(dev, "spurious interrupt"); - spin_unlock(&dev->spinlock); - return IRQ_NONE; - } - - das16m1_handler(dev, status); - - /* clear interrupt */ - outb(0, dev->iobase + DAS16M1_CLEAR_INTR); - - spin_unlock(&dev->spinlock); - return IRQ_HANDLED; -} - -static void munge_sample_array(short *array, unsigned int num_elements) -{ - unsigned int i; - - for (i = 0; i < num_elements; i++) { - array[i] = munge_sample(array[i]); - } + return insn->n; } static void das16m1_handler(struct comedi_device *dev, unsigned int status) { + struct das16m1_private_struct *devpriv = dev->private; struct comedi_subdevice *s; struct comedi_async *async; struct comedi_cmd *cmd; @@ -546,7 +418,6 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) s = dev->read_subdev; async = s->async; - async->events = 0; cmd = &async->cmd; /* figure out how many samples are in fifo */ @@ -579,8 +450,8 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) devpriv->adc_count += num_samples; if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { /* end of acquisition */ - das16m1_cancel(dev, s); + if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) { + /* end of acquisition */ async->events |= COMEDI_CB_EOA; } } @@ -588,68 +459,78 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status) /* this probably won't catch overruns since the card doesn't generate * overrun interrupts, but we might as well try */ if (status & OVRUN) { - das16m1_cancel(dev, s); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; comedi_error(dev, "fifo overflow"); } - comedi_event(dev, s); + cfc_handle_events(dev, s); +} + +static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s) +{ + unsigned long flags; + unsigned int status; + /* prevent race with interrupt handler */ + spin_lock_irqsave(&dev->spinlock, flags); + status = inb(dev->iobase + DAS16M1_CS); + das16m1_handler(dev, status); + spin_unlock_irqrestore(&dev->spinlock, flags); + + return s->async->buf_write_count - s->async->buf_read_count; } -/* This function takes a time in nanoseconds and sets the * - * 2 pacer clocks to the closest frequency possible. It also * - * returns the actual sampling period. */ -static unsigned int das16m1_set_pacer(struct comedi_device *dev, - unsigned int ns, int rounding_flags) +static irqreturn_t das16m1_interrupt(int irq, void *d) { - i8253_cascade_ns_to_timer_2div(DAS16M1_XTAL, &(devpriv->divisor1), - &(devpriv->divisor2), &ns, - rounding_flags & TRIG_ROUND_MASK); + int status; + struct comedi_device *dev = d; - /* Write the values of ctr1 and ctr2 into counters 1 and 2 */ - i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 1, devpriv->divisor1, - 2); - i8254_load(dev->iobase + DAS16M1_8254_SECOND, 0, 2, devpriv->divisor2, - 2); + if (!dev->attached) { + comedi_error(dev, "premature interrupt"); + return IRQ_HANDLED; + } + /* prevent race with comedi_poll() */ + spin_lock(&dev->spinlock); + + status = inb(dev->iobase + DAS16M1_CS); - return ns; + if ((status & (IRQDATA | OVRUN)) == 0) { + comedi_error(dev, "spurious interrupt"); + spin_unlock(&dev->spinlock); + return IRQ_NONE; + } + + das16m1_handler(dev, status); + + /* clear interrupt */ + outb(0, dev->iobase + DAS16M1_CLEAR_INTR); + + spin_unlock(&dev->spinlock); + return IRQ_HANDLED; } static int das16m1_irq_bits(unsigned int irq) { - int ret; - switch (irq) { case 10: - ret = 0x0; - break; + return 0x0; case 11: - ret = 0x1; - break; + return 0x1; case 12: - ret = 0x2; - break; + return 0x2; case 15: - ret = 0x3; - break; + return 0x3; case 2: - ret = 0x4; - break; + return 0x4; case 3: - ret = 0x5; - break; + return 0x5; case 5: - ret = 0x6; - break; + return 0x6; case 7: - ret = 0x7; - break; + return 0x7; default: - return -1; - break; + return 0x0; } - return ret << 4; } /* @@ -657,81 +538,58 @@ static int das16m1_irq_bits(unsigned int irq) * 0 I/O base * 1 IRQ */ - static int das16m1_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + struct das16m1_private_struct *devpriv; struct comedi_subdevice *s; int ret; - unsigned int irq; - unsigned long iobase; - - iobase = it->options[0]; - printk("comedi%d: das16m1:", dev->minor); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = alloc_private(dev, sizeof(struct das16m1_private_struct)); - if (ret < 0) + ret = comedi_request_region(dev, it->options[0], DAS16M1_SIZE); + if (ret) return ret; - - dev->board_name = thisboard->name; - - printk(" io 0x%lx-0x%lx 0x%lx-0x%lx", - iobase, iobase + DAS16M1_SIZE, - iobase + DAS16M1_82C55, iobase + DAS16M1_82C55 + DAS16M1_SIZE2); - if (!request_region(iobase, DAS16M1_SIZE, driver_das16m1.driver_name)) { - printk(" I/O port conflict\n"); - return -EIO; - } - if (!request_region(iobase + DAS16M1_82C55, DAS16M1_SIZE2, - driver_das16m1.driver_name)) { - release_region(iobase, DAS16M1_SIZE); - printk(" I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - /* now for the irq */ - irq = it->options[1]; - /* make sure it is valid */ - if (das16m1_irq_bits(irq) >= 0) { - ret = request_irq(irq, das16m1_interrupt, 0, - driver_das16m1.driver_name, dev); - if (ret < 0) { - printk(", irq unavailable\n"); - return ret; - } - dev->irq = irq; - printk(", irq %u\n", irq); - } else if (irq == 0) { - printk(", no irq\n"); - } else { - printk(", invalid irq\n" - " valid irqs are 2, 3, 5, 7, 10, 11, 12, or 15\n"); - return -EINVAL; + /* Request an additional region for the 8255 */ + ret = __comedi_request_region(dev, dev->iobase + DAS16M1_82C55, + DAS16M1_SIZE2); + if (ret) + return ret; + devpriv->extra_iobase = dev->iobase + DAS16M1_82C55; + + /* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */ + if ((1 << it->options[1]) & 0xdcfc) { + ret = request_irq(it->options[1], das16m1_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - ret = alloc_subdevices(dev, 4); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - s = dev->subdevices + 0; - dev->read_subdev = s; + s = &dev->subdevices[0]; /* ai */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_DIFF; s->n_chan = 8; - s->subdev_flags = SDF_DIFF; - s->len_chanlist = 256; s->maxdata = (1 << 12) - 1; s->range_table = &range_das16m1; s->insn_read = das16m1_ai_rinsn; - s->do_cmdtest = das16m1_cmd_test; - s->do_cmd = das16m1_cmd_exec; - s->cancel = das16m1_cancel; - s->poll = das16m1_poll; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 256; + s->do_cmdtest = das16m1_cmd_test; + s->do_cmd = das16m1_cmd_exec; + s->cancel = das16m1_cancel; + s->poll = das16m1_poll; + } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* di */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -740,7 +598,7 @@ static int das16m1_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = das16m1_di_rbits; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* do */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; @@ -749,46 +607,42 @@ static int das16m1_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = das16m1_do_wbits; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* 8255 */ - subdev_8255_init(dev, s, NULL, dev->iobase + DAS16M1_82C55); + ret = subdev_8255_init(dev, s, NULL, devpriv->extra_iobase); + if (ret) + return ret; /* disable upper half of hardware conversion counter so it doesn't mess with us */ outb(TOTAL_CLEAR, dev->iobase + DAS16M1_8254_FIRST_CNTRL); /* initialize digital output lines */ - outb(devpriv->do_bits, dev->iobase + DAS16M1_DIO); + outb(0, dev->iobase + DAS16M1_DIO); /* set the interrupt level */ - if (dev->irq) - devpriv->control_state = das16m1_irq_bits(dev->irq); - else - devpriv->control_state = 0; + devpriv->control_state = das16m1_irq_bits(dev->irq) << 4; outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL); return 0; } -static int das16m1_detach(struct comedi_device *dev) +static void das16m1_detach(struct comedi_device *dev) { - printk("comedi%d: das16m1: remove\n", dev->minor); - -/* das16m1_reset(dev); */ - - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 3); + struct das16m1_private_struct *devpriv = dev->private; - if (dev->irq) - free_irq(dev->irq, dev); - - if (dev->iobase) { - release_region(dev->iobase, DAS16M1_SIZE); - release_region(dev->iobase + DAS16M1_82C55, DAS16M1_SIZE2); - } - - return 0; + if (devpriv && devpriv->extra_iobase) + release_region(devpriv->extra_iobase, DAS16M1_SIZE2); + comedi_legacy_detach(dev); } +static struct comedi_driver das16m1_driver = { + .driver_name = "das16m1", + .module = THIS_MODULE, + .attach = das16m1_attach, + .detach = das16m1_detach, +}; +module_comedi_driver(das16m1_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 60c2b12d6ff..859519026c4 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -15,12 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: das1800 @@ -100,11 +94,12 @@ TODO: read insn for analog out */ +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/slab.h> +#include <linux/io.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <asm/dma.h> #include "8253.h" @@ -113,7 +108,6 @@ TODO: /* misc. defines */ #define DAS1800_SIZE 16 /* uses 16 io addresses */ #define FIFO_SIZE 1024 /* 1024 sample fifo */ -#define TIMER_BASE 200 /* 5 Mhz master clock */ #define UNIPOLAR 0x4 /* bit that determines whether input range is uni/bipolar */ #define DMA_BUF_SIZE 0x1ff00 /* size in bytes of dma buffers */ @@ -182,76 +176,31 @@ enum { das1802hr, das1802hr_da, das1801hc, das1802hc, das1801ao, das1802ao }; -static int das1800_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int das1800_detach(struct comedi_device *dev); -static int das1800_probe(struct comedi_device *dev); -static int das1800_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static irqreturn_t das1800_interrupt(int irq, void *d); -static int das1800_ai_poll(struct comedi_device *dev, - struct comedi_subdevice *s); -static void das1800_ai_handler(struct comedi_device *dev); -static void das1800_handle_dma(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int status); -static void das1800_flush_dma(struct comedi_device *dev, - struct comedi_subdevice *s); -static void das1800_flush_dma_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int channel, uint16_t * buffer); -static void das1800_handle_fifo_half_full(struct comedi_device *dev, - struct comedi_subdevice *s); -static void das1800_handle_fifo_not_empty(struct comedi_device *dev, - struct comedi_subdevice *s); -static int das1800_ai_do_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int das1800_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int das1800_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das1800_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das1800_di_rbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int das1800_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int das1800_set_frequency(struct comedi_device *dev); -static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode); -static unsigned int suggest_transfer_size(struct comedi_cmd *cmd); - /* analog input ranges */ static const struct comedi_lrange range_ai_das1801 = { - 8, - { - RANGE(-5, 5), - RANGE(-1, 1), - RANGE(-0.1, 0.1), - RANGE(-0.02, 0.02), - RANGE(0, 5), - RANGE(0, 1), - RANGE(0, 0.1), - RANGE(0, 0.02), - } + 8, { + BIP_RANGE(5), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02), + UNI_RANGE(5), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) + } }; static const struct comedi_lrange range_ai_das1802 = { - 8, - { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25), - } + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; struct das1800_board { @@ -471,16 +420,10 @@ static const struct das1800_board das1800_boards[] = { }, }; -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct das1800_board *)dev->board_ptr) - struct das1800_private { volatile unsigned int count; /* number of data points left to be taken */ unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */ unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */ - int do_bits; /* digital output bits */ int irq_dma_bits; /* bits for control register b */ /* dma bits for control register b, stored so that dma can be * turned on and off */ @@ -493,465 +436,216 @@ struct das1800_private { uint16_t *dma_current_buf; /* pointer to dma buffer currently being used */ unsigned int dma_transfer_size; /* size of transfer currently used, in bytes */ unsigned long iobase2; /* secondary io address used for analog out on 'ao' boards */ - short ao_update_bits; /* remembers the last write to the 'update' dac */ -}; - -#define devpriv ((struct das1800_private *)dev->private) - -/* analog out range for boards with basic analog out */ -static const struct comedi_lrange range_ao_1 = { - 1, - { - RANGE(-10, 10), - } + unsigned short ao_update_bits; /* remembers the last write to the + * 'update' dac */ }; /* analog out range for 'ao' boards */ /* static const struct comedi_lrange range_ao_2 = { - 2, - { - RANGE(-10, 10), - RANGE(-5, 5), + 2, { + BIP_RANGE(10), + BIP_RANGE(5) } }; */ -static struct comedi_driver driver_das1800 = { - .driver_name = "das1800", - .module = THIS_MODULE, - .attach = das1800_attach, - .detach = das1800_detach, - .num_names = ARRAY_SIZE(das1800_boards), - .board_name = &das1800_boards[0].name, - .offset = sizeof(struct das1800_board), -}; - -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_das1800_init_module(void) +static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev, + uint16_t sample) { - return comedi_driver_register(&driver_das1800); -} + const struct das1800_board *thisboard = comedi_board(dev); -static void __exit driver_das1800_cleanup_module(void) -{ - comedi_driver_unregister(&driver_das1800); + sample += 1 << (thisboard->resolution - 1); + return sample; } -module_init(driver_das1800_init_module); -module_exit(driver_das1800_cleanup_module); - -static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, - unsigned int dma1) +static void munge_data(struct comedi_device *dev, uint16_t *array, + unsigned int num_elements) { - unsigned long flags; + unsigned int i; + int unipolar; - /* need an irq to do dma */ - if (dev->irq && dma0) { - /* encode dma0 and dma1 into 2 digit hexadecimal for switch */ - switch ((dma0 & 0x7) | (dma1 << 4)) { - case 0x5: /* dma0 == 5 */ - devpriv->dma_bits |= DMA_CH5; - break; - case 0x6: /* dma0 == 6 */ - devpriv->dma_bits |= DMA_CH6; - break; - case 0x7: /* dma0 == 7 */ - devpriv->dma_bits |= DMA_CH7; - break; - case 0x65: /* dma0 == 5, dma1 == 6 */ - devpriv->dma_bits |= DMA_CH5_CH6; - break; - case 0x76: /* dma0 == 6, dma1 == 7 */ - devpriv->dma_bits |= DMA_CH6_CH7; - break; - case 0x57: /* dma0 == 7, dma1 == 5 */ - devpriv->dma_bits |= DMA_CH7_CH5; - break; - default: - printk(" only supports dma channels 5 through 7\n" - " Dual dma only allows the following combinations:\n" - " dma 5,6 / 6,7 / or 7,5\n"); - return -EINVAL; - break; - } - if (request_dma(dma0, driver_das1800.driver_name)) { - printk(" failed to allocate dma channel %i\n", dma0); - return -EINVAL; - } - devpriv->dma0 = dma0; - devpriv->dma_current = dma0; - if (dma1) { - if (request_dma(dma1, driver_das1800.driver_name)) { - printk(" failed to allocate dma channel %i\n", - dma1); - return -EINVAL; - } - devpriv->dma1 = dma1; - } - devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA); - if (devpriv->ai_buf0 == NULL) - return -ENOMEM; - devpriv->dma_current_buf = devpriv->ai_buf0; - if (dma1) { - devpriv->ai_buf1 = - kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA); - if (devpriv->ai_buf1 == NULL) - return -ENOMEM; - } - flags = claim_dma_lock(); - disable_dma(devpriv->dma0); - set_dma_mode(devpriv->dma0, DMA_MODE_READ); - if (dma1) { - disable_dma(devpriv->dma1); - set_dma_mode(devpriv->dma1, DMA_MODE_READ); - } - release_dma_lock(flags); + /* see if card is using a unipolar or bipolar range so we can munge data correctly */ + unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB; + + /* convert to unsigned type if we are in a bipolar mode */ + if (!unipolar) { + for (i = 0; i < num_elements; i++) + array[i] = munge_bipolar_sample(dev, array[i]); } - return 0; } -static int das1800_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static void das1800_handle_fifo_half_full(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_subdevice *s; - unsigned long iobase = it->options[0]; - unsigned int irq = it->options[1]; - unsigned int dma0 = it->options[2]; - unsigned int dma1 = it->options[3]; - unsigned long iobase2; - int board; - int retval; - - /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(struct das1800_private)) < 0) - return -ENOMEM; - - printk("comedi%d: %s: io 0x%lx", dev->minor, driver_das1800.driver_name, - iobase); - if (irq) { - printk(", irq %u", irq); - if (dma0) { - printk(", dma %u", dma0); - if (dma1) - printk(" and %u", dma1); - } - } - printk("\n"); - - if (iobase == 0) { - printk(" io base address required\n"); - return -EINVAL; - } - - /* check if io addresses are available */ - if (!request_region(iobase, DAS1800_SIZE, driver_das1800.driver_name)) { - printk - (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", - iobase, iobase + DAS1800_SIZE - 1); - return -EIO; - } - dev->iobase = iobase; + struct das1800_private *devpriv = dev->private; + int numPoints = 0; /* number of points to read */ + struct comedi_cmd *cmd = &s->async->cmd; - board = das1800_probe(dev); - if (board < 0) { - printk(" unable to determine board type\n"); - return -ENODEV; - } + numPoints = FIFO_SIZE / 2; + /* if we only need some of the points */ + if (cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints) + numPoints = devpriv->count; + insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, numPoints); + munge_data(dev, devpriv->ai_buf0, numPoints); + cfc_write_array_to_buffer(s, devpriv->ai_buf0, + numPoints * sizeof(devpriv->ai_buf0[0])); + if (cmd->stop_src == TRIG_COUNT) + devpriv->count -= numPoints; + return; +} - dev->board_ptr = das1800_boards + board; - dev->board_name = thisboard->name; +static void das1800_handle_fifo_not_empty(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct das1800_private *devpriv = dev->private; + unsigned short dpnt; + int unipolar; + struct comedi_cmd *cmd = &s->async->cmd; - /* if it is an 'ao' board with fancy analog out then we need extra io ports */ - if (thisboard->ao_ability == 2) { - iobase2 = iobase + IOBASE2; - if (!request_region(iobase2, DAS1800_SIZE, - driver_das1800.driver_name)) { - printk - (" I/O port conflict: failed to allocate ports 0x%lx to 0x%lx\n", - iobase2, iobase2 + DAS1800_SIZE - 1); - return -EIO; - } - devpriv->iobase2 = iobase2; - } + unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB; - /* grab our IRQ */ - if (irq) { - if (request_irq(irq, das1800_interrupt, 0, - driver_das1800.driver_name, dev)) { - printk(" unable to allocate irq %u\n", irq); - return -EINVAL; - } + while (inb(dev->iobase + DAS1800_STATUS) & FNE) { + if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) + break; + dpnt = inw(dev->iobase + DAS1800_FIFO); + /* convert to unsigned type if we are in a bipolar mode */ + if (!unipolar) + ; + dpnt = munge_bipolar_sample(dev, dpnt); + cfc_write_to_buffer(s, dpnt); + if (cmd->stop_src == TRIG_COUNT) + devpriv->count--; } - dev->irq = irq; - /* set bits that tell card which irq to use */ - switch (irq) { - case 0: - break; - case 3: - devpriv->irq_dma_bits |= 0x8; - break; - case 5: - devpriv->irq_dma_bits |= 0x10; - break; - case 7: - devpriv->irq_dma_bits |= 0x18; - break; - case 10: - devpriv->irq_dma_bits |= 0x28; - break; - case 11: - devpriv->irq_dma_bits |= 0x30; - break; - case 15: - devpriv->irq_dma_bits |= 0x38; - break; - default: - printk(" irq out of range\n"); - return -EINVAL; - break; - } + return; +} - retval = das1800_init_dma(dev, dma0, dma1); - if (retval < 0) - return retval; +/* Utility function used by das1800_flush_dma() and das1800_handle_dma(). + * Assumes dma lock is held */ +static void das1800_flush_dma_channel(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int channel, uint16_t *buffer) +{ + struct das1800_private *devpriv = dev->private; + unsigned int num_bytes, num_samples; + struct comedi_cmd *cmd = &s->async->cmd; - if (devpriv->ai_buf0 == NULL) { - devpriv->ai_buf0 = - kmalloc(FIFO_SIZE * sizeof(uint16_t), GFP_KERNEL); - if (devpriv->ai_buf0 == NULL) - return -ENOMEM; - } + disable_dma(channel); - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; + /* clear flip-flop to make sure 2-byte registers + * get set correctly */ + clear_dma_ff(channel); - /* analog input subdevice */ - s = dev->subdevices + 0; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND | SDF_CMD_READ; - if (thisboard->common) - s->subdev_flags |= SDF_COMMON; - s->n_chan = thisboard->qram_len; - s->len_chanlist = thisboard->qram_len; - s->maxdata = (1 << thisboard->resolution) - 1; - s->range_table = thisboard->range_ai; - s->do_cmd = das1800_ai_do_cmd; - s->do_cmdtest = das1800_ai_do_cmdtest; - s->insn_read = das1800_ai_rinsn; - s->poll = das1800_ai_poll; - s->cancel = das1800_cancel; + /* figure out how many points to read */ + num_bytes = devpriv->dma_transfer_size - get_dma_residue(channel); + num_samples = num_bytes / sizeof(short); - /* analog out */ - s = dev->subdevices + 1; - if (thisboard->ao_ability == 1) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->ao_n_chan; - s->maxdata = (1 << thisboard->resolution) - 1; - s->range_table = &range_ao_1; - s->insn_write = das1800_ao_winsn; - } else { - s->type = COMEDI_SUBD_UNUSED; - } + /* if we only need some of the points */ + if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_samples) + num_samples = devpriv->count; - /* di */ - 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 = das1800_di_rbits; + munge_data(dev, buffer, num_samples); + cfc_write_array_to_buffer(s, buffer, num_bytes); + if (cmd->stop_src == TRIG_COUNT) + devpriv->count -= num_samples; - /* do */ - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = thisboard->do_n_chan; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = das1800_do_wbits; + return; +} - das1800_cancel(dev, dev->read_subdev); +/* flushes remaining data from board when external trigger has stopped acquisition + * and we are using dma transfers */ +static void das1800_flush_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct das1800_private *devpriv = dev->private; + unsigned long flags; + const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; - /* initialize digital out channels */ - outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL); + flags = claim_dma_lock(); + das1800_flush_dma_channel(dev, s, devpriv->dma_current, + devpriv->dma_current_buf); - /* initialize analog out channels */ - if (thisboard->ao_ability == 1) { - /* select 'update' dac channel for baseAddress + 0x0 */ - outb(DAC(thisboard->ao_n_chan - 1), - dev->iobase + DAS1800_SELECT); - outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC); + if (dual_dma) { + /* switch to other channel and flush it */ + if (devpriv->dma_current == devpriv->dma0) { + devpriv->dma_current = devpriv->dma1; + devpriv->dma_current_buf = devpriv->ai_buf1; + } else { + devpriv->dma_current = devpriv->dma0; + devpriv->dma_current_buf = devpriv->ai_buf0; + } + das1800_flush_dma_channel(dev, s, devpriv->dma_current, + devpriv->dma_current_buf); } - return 0; -}; - -static int das1800_detach(struct comedi_device *dev) -{ - /* only free stuff if it has been allocated by _attach */ - if (dev->iobase) - release_region(dev->iobase, DAS1800_SIZE); - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->private) { - if (devpriv->iobase2) - release_region(devpriv->iobase2, DAS1800_SIZE); - if (devpriv->dma0) - free_dma(devpriv->dma0); - if (devpriv->dma1) - free_dma(devpriv->dma1); - kfree(devpriv->ai_buf0); - kfree(devpriv->ai_buf1); - } + release_dma_lock(flags); - printk("comedi%d: %s: remove\n", dev->minor, - driver_das1800.driver_name); + /* get any remaining samples in fifo */ + das1800_handle_fifo_not_empty(dev, s); - return 0; -}; + return; +} -/* probes and checks das-1800 series board type - */ -static int das1800_probe(struct comedi_device *dev) +static void das1800_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s, unsigned int status) { - int id; - int board; + struct das1800_private *devpriv = dev->private; + unsigned long flags; + const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; - id = (inb(dev->iobase + DAS1800_DIGITAL) >> 4) & 0xf; /* get id bits */ - board = ((struct das1800_board *)dev->board_ptr) - das1800_boards; + flags = claim_dma_lock(); + das1800_flush_dma_channel(dev, s, devpriv->dma_current, + devpriv->dma_current_buf); + /* re-enable dma channel */ + set_dma_addr(devpriv->dma_current, + virt_to_bus(devpriv->dma_current_buf)); + set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size); + enable_dma(devpriv->dma_current); + release_dma_lock(flags); - switch (id) { - case 0x3: - if (board == das1801st_da || board == das1802st_da || - board == das1701st_da || board == das1702st_da) { - printk(" Board model: %s\n", - das1800_boards[board].name); - return board; - } - printk - (" Board model (probed, not recommended): das-1800st-da series\n"); - return das1801st; - break; - case 0x4: - if (board == das1802hr_da || board == das1702hr_da) { - printk(" Board model: %s\n", - das1800_boards[board].name); - return board; - } - printk - (" Board model (probed, not recommended): das-1802hr-da\n"); - return das1802hr; - break; - case 0x5: - if (board == das1801ao || board == das1802ao || - board == das1701ao || board == das1702ao) { - printk(" Board model: %s\n", - das1800_boards[board].name); - return board; - } - printk - (" Board model (probed, not recommended): das-1800ao series\n"); - return das1801ao; - break; - case 0x6: - if (board == das1802hr || board == das1702hr) { - printk(" Board model: %s\n", - das1800_boards[board].name); - return board; - } - printk(" Board model (probed, not recommended): das-1802hr\n"); - return das1802hr; - break; - case 0x7: - if (board == das1801st || board == das1802st || - board == das1701st || board == das1702st) { - printk(" Board model: %s\n", - das1800_boards[board].name); - return board; - } - printk - (" Board model (probed, not recommended): das-1800st series\n"); - return das1801st; - break; - case 0x8: - if (board == das1801hc || board == das1802hc) { - printk(" Board model: %s\n", - das1800_boards[board].name); - return board; + if (status & DMATC) { + /* clear DMATC interrupt bit */ + outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS); + /* switch dma channels for next time, if appropriate */ + if (dual_dma) { + /* read data from the other channel next time */ + if (devpriv->dma_current == devpriv->dma0) { + devpriv->dma_current = devpriv->dma1; + devpriv->dma_current_buf = devpriv->ai_buf1; + } else { + devpriv->dma_current = devpriv->dma0; + devpriv->dma_current_buf = devpriv->ai_buf0; + } } - printk - (" Board model (probed, not recommended): das-1800hc series\n"); - return das1801hc; - break; - default: - printk - (" Board model: probe returned 0x%x (unknown, please report)\n", - id); - return board; - break; } - return -1; -} -static int das1800_ai_poll(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned long flags; - - /* prevent race with interrupt handler */ - spin_lock_irqsave(&dev->spinlock, flags); - das1800_ai_handler(dev); - spin_unlock_irqrestore(&dev->spinlock, flags); - - return s->async->buf_write_count - s->async->buf_read_count; + return; } -static irqreturn_t das1800_interrupt(int irq, void *d) +static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct comedi_device *dev = d; - unsigned int status; - - if (dev->attached == 0) { - comedi_error(dev, "premature interrupt"); - return IRQ_HANDLED; - } - - /* Prevent race with das1800_ai_poll() on multi processor systems. - * Also protects indirect addressing in das1800_ai_handler */ - spin_lock(&dev->spinlock); - status = inb(dev->iobase + DAS1800_STATUS); + struct das1800_private *devpriv = dev->private; - /* if interrupt was not caused by das-1800 */ - if (!(status & INT)) { - spin_unlock(&dev->spinlock); - return IRQ_NONE; - } - /* clear the interrupt status bit INT */ - outb(CLEAR_INTR_MASK & ~INT, dev->iobase + DAS1800_STATUS); - /* handle interrupt */ - das1800_ai_handler(dev); - - spin_unlock(&dev->spinlock); - return IRQ_HANDLED; + outb(0x0, dev->iobase + DAS1800_STATUS); /* disable conversions */ + outb(0x0, dev->iobase + DAS1800_CONTROL_B); /* disable interrupts and dma */ + outb(0x0, dev->iobase + DAS1800_CONTROL_A); /* disable and clear fifo and stop triggering */ + if (devpriv->dma0) + disable_dma(devpriv->dma0); + if (devpriv->dma1) + disable_dma(devpriv->dma1); + return 0; } /* the guts of the interrupt handler, that is shared with das1800_ai_poll */ static void das1800_ai_handler(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + 0; /* analog input subdevice */ + struct das1800_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int status = inb(dev->iobase + DAS1800_STATUS); - async->events = 0; /* select adc for base address + 0 */ outb(ADC, dev->iobase + DAS1800_SELECT); /* dma buffer full */ @@ -970,9 +664,8 @@ static void das1800_ai_handler(struct comedi_device *dev) /* clear OVF interrupt bit */ outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS); comedi_error(dev, "DAS1800 FIFO overflow"); - das1800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return; } /* stop taking data if appropriate */ @@ -985,193 +678,102 @@ static void das1800_ai_handler(struct comedi_device *dev) das1800_flush_dma(dev, s); else das1800_handle_fifo_not_empty(dev, s); - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } else if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) { /* stop_src TRIG_COUNT */ - das1800_cancel(dev, s); /* disable hardware conversions */ async->events |= COMEDI_CB_EOA; } - comedi_event(dev, s); - - return; + cfc_handle_events(dev, s); } -static void das1800_handle_dma(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int status) +static int das1800_ai_poll(struct comedi_device *dev, + struct comedi_subdevice *s) { unsigned long flags; - const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; - - flags = claim_dma_lock(); - das1800_flush_dma_channel(dev, s, devpriv->dma_current, - devpriv->dma_current_buf); - /* re-enable dma channel */ - set_dma_addr(devpriv->dma_current, - virt_to_bus(devpriv->dma_current_buf)); - set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_current); - release_dma_lock(flags); - if (status & DMATC) { - /* clear DMATC interrupt bit */ - outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS); - /* switch dma channels for next time, if appropriate */ - if (dual_dma) { - /* read data from the other channel next time */ - if (devpriv->dma_current == devpriv->dma0) { - devpriv->dma_current = devpriv->dma1; - devpriv->dma_current_buf = devpriv->ai_buf1; - } else { - devpriv->dma_current = devpriv->dma0; - devpriv->dma_current_buf = devpriv->ai_buf0; - } - } - } - - return; -} + /* prevent race with interrupt handler */ + spin_lock_irqsave(&dev->spinlock, flags); + das1800_ai_handler(dev); + spin_unlock_irqrestore(&dev->spinlock, flags); -static inline uint16_t munge_bipolar_sample(const struct comedi_device *dev, - uint16_t sample) -{ - sample += 1 << (thisboard->resolution - 1); - return sample; + return s->async->buf_write_count - s->async->buf_read_count; } -static void munge_data(struct comedi_device *dev, uint16_t * array, - unsigned int num_elements) +static irqreturn_t das1800_interrupt(int irq, void *d) { - unsigned int i; - int unipolar; - - /* see if card is using a unipolar or bipolar range so we can munge data correctly */ - unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB; + struct comedi_device *dev = d; + unsigned int status; - /* convert to unsigned type if we are in a bipolar mode */ - if (!unipolar) { - for (i = 0; i < num_elements; i++) { - array[i] = munge_bipolar_sample(dev, array[i]); - } + if (!dev->attached) { + comedi_error(dev, "premature interrupt"); + return IRQ_HANDLED; } -} -/* Utility function used by das1800_flush_dma() and das1800_handle_dma(). - * Assumes dma lock is held */ -static void das1800_flush_dma_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int channel, uint16_t * buffer) -{ - unsigned int num_bytes, num_samples; - struct comedi_cmd *cmd = &s->async->cmd; - - disable_dma(channel); - - /* clear flip-flop to make sure 2-byte registers - * get set correctly */ - clear_dma_ff(channel); - - /* figure out how many points to read */ - num_bytes = devpriv->dma_transfer_size - get_dma_residue(channel); - num_samples = num_bytes / sizeof(short); - - /* if we only need some of the points */ - if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_samples) - num_samples = devpriv->count; + /* Prevent race with das1800_ai_poll() on multi processor systems. + * Also protects indirect addressing in das1800_ai_handler */ + spin_lock(&dev->spinlock); + status = inb(dev->iobase + DAS1800_STATUS); - munge_data(dev, buffer, num_samples); - cfc_write_array_to_buffer(s, buffer, num_bytes); - if (s->async->cmd.stop_src == TRIG_COUNT) - devpriv->count -= num_samples; + /* if interrupt was not caused by das-1800 */ + if (!(status & INT)) { + spin_unlock(&dev->spinlock); + return IRQ_NONE; + } + /* clear the interrupt status bit INT */ + outb(CLEAR_INTR_MASK & ~INT, dev->iobase + DAS1800_STATUS); + /* handle interrupt */ + das1800_ai_handler(dev); - return; + spin_unlock(&dev->spinlock); + return IRQ_HANDLED; } -/* flushes remaining data from board when external trigger has stopped acquisition - * and we are using dma transfers */ -static void das1800_flush_dma(struct comedi_device *dev, - struct comedi_subdevice *s) +/* converts requested conversion timing to timing compatible with + * hardware, used only when card is in 'burst mode' + */ +static unsigned int burst_convert_arg(unsigned int convert_arg, int flags) { - unsigned long flags; - const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; + unsigned int micro_sec; - flags = claim_dma_lock(); - das1800_flush_dma_channel(dev, s, devpriv->dma_current, - devpriv->dma_current_buf); + /* in burst mode, the maximum conversion time is 64 microseconds */ + if (convert_arg > 64000) + convert_arg = 64000; - if (dual_dma) { - /* switch to other channel and flush it */ - if (devpriv->dma_current == devpriv->dma0) { - devpriv->dma_current = devpriv->dma1; - devpriv->dma_current_buf = devpriv->ai_buf1; - } else { - devpriv->dma_current = devpriv->dma0; - devpriv->dma_current_buf = devpriv->ai_buf0; - } - das1800_flush_dma_channel(dev, s, devpriv->dma_current, - devpriv->dma_current_buf); + /* the conversion time must be an integral number of microseconds */ + switch (flags & TRIG_ROUND_MASK) { + case TRIG_ROUND_NEAREST: + default: + micro_sec = (convert_arg + 500) / 1000; + break; + case TRIG_ROUND_DOWN: + micro_sec = convert_arg / 1000; + break; + case TRIG_ROUND_UP: + micro_sec = (convert_arg - 1) / 1000 + 1; + break; } - release_dma_lock(flags); - - /* get any remaining samples in fifo */ - das1800_handle_fifo_not_empty(dev, s); - - return; -} - -static void das1800_handle_fifo_half_full(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - int numPoints = 0; /* number of points to read */ - struct comedi_cmd *cmd = &s->async->cmd; - - numPoints = FIFO_SIZE / 2; - /* if we only need some of the points */ - if (cmd->stop_src == TRIG_COUNT && devpriv->count < numPoints) - numPoints = devpriv->count; - insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, numPoints); - munge_data(dev, devpriv->ai_buf0, numPoints); - cfc_write_array_to_buffer(s, devpriv->ai_buf0, - numPoints * sizeof(devpriv->ai_buf0[0])); - if (cmd->stop_src == TRIG_COUNT) - devpriv->count -= numPoints; - return; + /* return number of nanoseconds */ + return micro_sec * 1000; } -static void das1800_handle_fifo_not_empty(struct comedi_device *dev, - struct comedi_subdevice *s) +static int das1800_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - short dpnt; - int unipolar; - struct comedi_cmd *cmd = &s->async->cmd; + unsigned int unipolar0 = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR; + int i; - unipolar = inb(dev->iobase + DAS1800_CONTROL_C) & UB; + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int unipolar = CR_RANGE(cmd->chanlist[i]) & UNIPOLAR; - while (inb(dev->iobase + DAS1800_STATUS) & FNE) { - if (cmd->stop_src == TRIG_COUNT && devpriv->count == 0) - break; - dpnt = inw(dev->iobase + DAS1800_FIFO); - /* convert to unsigned type if we are in a bipolar mode */ - if (!unipolar) ; - dpnt = munge_bipolar_sample(dev, dpnt); - cfc_write_to_buffer(s, dpnt); - if (cmd->stop_src == TRIG_COUNT) - devpriv->count--; + if (unipolar != unipolar0) { + dev_dbg(dev->class_dev, + "unipolar and bipolar ranges cannot be mixed in the chanlist\n"); + return -EINVAL; + } } - return; -} - -static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - outb(0x0, dev->iobase + DAS1800_STATUS); /* disable conversions */ - outb(0x0, dev->iobase + DAS1800_CONTROL_B); /* disable interrupts and dma */ - outb(0x0, dev->iobase + DAS1800_CONTROL_A); /* disable and clear fifo and stop triggering */ - if (devpriv->dma0) - disable_dma(devpriv->dma0); - if (devpriv->dma1) - disable_dma(devpriv->dma1); return 0; } @@ -1180,97 +782,57 @@ 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); + struct das1800_private *devpriv = dev->private; int err = 0; - int tmp; - unsigned int tmp_arg; - int i; - int unipolar; + unsigned int arg; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | 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_EXT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* 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 */ - /* uniqueness check */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err++; - /* compatibility check */ if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_TIMER) - err++; + err |= -EINVAL; if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < thisboard->ai_speed) { - cmd->convert_arg = thisboard->ai_speed; - err++; - } - } - if (!cmd->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + thisboard->ai_speed); + + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); switch (cmd->stop_src) { case TRIG_COUNT: - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); break; case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); break; default: break; @@ -1281,72 +843,48 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->convert_src == TRIG_TIMER) { - /* if we are not in burst mode */ - if (cmd->scan_begin_src == TRIG_FOLLOW) { - tmp_arg = cmd->convert_arg; - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd-> - flags & TRIG_ROUND_MASK); - if (tmp_arg != cmd->convert_arg) - err++; - } - /* if we are in burst mode */ - else { - /* check that convert_arg is compatible */ - tmp_arg = cmd->convert_arg; - cmd->convert_arg = - burst_convert_arg(cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp_arg != cmd->convert_arg) - err++; + if (cmd->scan_begin_src == TRIG_FOLLOW && + cmd->convert_src == TRIG_TIMER) { + /* we are not in burst mode */ + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->convert_arg, cmd->flags); + if (arg != cmd->convert_arg) + err++; + } else if (cmd->convert_src == TRIG_TIMER) { + /* we are in burst mode */ + arg = cmd->convert_arg; + cmd->convert_arg = burst_convert_arg(cmd->convert_arg, + cmd->flags); + if (arg != cmd->convert_arg) + err++; - if (cmd->scan_begin_src == TRIG_TIMER) { - /* if scans are timed faster than conversion rate allows */ - if (cmd->convert_arg * cmd->chanlist_len > - cmd->scan_begin_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * - cmd->chanlist_len; - err++; - } - tmp_arg = cmd->scan_begin_arg; - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv-> - divisor1), - &(devpriv-> - divisor2), - &(cmd-> - scan_begin_arg), - cmd-> - flags & - TRIG_ROUND_MASK); - if (tmp_arg != cmd->scan_begin_arg) - err++; + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->chanlist_len; + if (arg > cmd->scan_begin_arg) { + cmd->scan_begin_arg = arg; + err++; } + + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_5MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &cmd->scan_begin_arg, + cmd->flags); + if (arg != cmd->scan_begin_arg) + err++; } } if (err) return 4; - /* make sure user is not trying to mix unipolar and bipolar ranges */ - if (cmd->chanlist) { - unipolar = CR_RANGE(cmd->chanlist[0]) & UNIPOLAR; - for (i = 1; i < cmd->chanlist_len; i++) { - if (unipolar != (CR_RANGE(cmd->chanlist[i]) & UNIPOLAR)) { - comedi_error(dev, - "unipolar and bipolar ranges cannot be mixed in the chanlist"); - err++; - break; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das1800_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -1354,20 +892,15 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, return 0; } -/* analog input cmd interface */ - -/* first, some utility functions used in the main ai_do_cmd() */ - /* returns appropriate bits for control register a, depending on command */ -static int control_a_bits(struct comedi_cmd cmd) +static int control_a_bits(const struct comedi_cmd *cmd) { int control_a; control_a = FFEN; /* enable fifo */ - if (cmd.stop_src == TRIG_EXT) { + if (cmd->stop_src == TRIG_EXT) control_a |= ATEN; - } - switch (cmd.start_src) { + switch (cmd->start_src) { case TRIG_EXT: control_a |= TGEN | CGSL; break; @@ -1382,7 +915,7 @@ static int control_a_bits(struct comedi_cmd cmd) } /* returns appropriate bits for control register c, depending on command */ -static int control_c_bits(struct comedi_cmd cmd) +static int control_c_bits(const struct comedi_cmd *cmd) { int control_c; int aref; @@ -1390,18 +923,18 @@ static int control_c_bits(struct comedi_cmd cmd) /* set clock source to internal or external, select analog reference, * select unipolar / bipolar */ - aref = CR_AREF(cmd.chanlist[0]); + aref = CR_AREF(cmd->chanlist[0]); control_c = UQEN; /* enable upper qram addresses */ if (aref != AREF_DIFF) control_c |= SD; if (aref == AREF_COMMON) control_c |= CMEN; /* if a unipolar range was selected */ - if (CR_RANGE(cmd.chanlist[0]) & UNIPOLAR) + if (CR_RANGE(cmd->chanlist[0]) & UNIPOLAR) control_c |= UB; - switch (cmd.scan_begin_src) { + switch (cmd->scan_begin_src) { case TRIG_FOLLOW: /* not in burst mode */ - switch (cmd.convert_src) { + switch (cmd->convert_src) { case TRIG_TIMER: /* trig on cascaded counters */ control_c |= IPCLK; @@ -1429,51 +962,73 @@ static int control_c_bits(struct comedi_cmd cmd) return control_c; } -/* sets up counters */ -static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd) +static void das1800_setup_counters(struct comedi_device *dev, + const struct comedi_cmd *cmd) { - /* setup cascaded counters for conversion/scan frequency */ - switch (cmd.scan_begin_src) { + struct das1800_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + DAS1800_COUNTER; + + /* setup cascaded counters for conversion/scan frequency */ + if ((cmd->scan_begin_src == TRIG_FOLLOW || + cmd->scan_begin_src == TRIG_TIMER) && + cmd->convert_src == TRIG_TIMER) { + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); + } + + /* setup counter 0 for 'about triggering' */ + if (cmd->stop_src == TRIG_EXT) { + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + i8254_write(timer_base, 0, 0, 1); + } +} + +/* utility function that suggests a dma transfer size based on the conversion period 'ns' */ +static unsigned int suggest_transfer_size(const struct comedi_cmd *cmd) +{ + unsigned int size = DMA_BUF_SIZE; + static const int sample_size = 2; /* size in bytes of one sample from board */ + unsigned int fill_time = 300000000; /* target time in nanoseconds for filling dma buffer */ + unsigned int max_size; /* maximum size we will allow for a transfer */ + + /* make dma buffer fill in 0.3 seconds for timed modes */ + switch (cmd->scan_begin_src) { case TRIG_FOLLOW: /* not in burst mode */ - if (cmd.convert_src == TRIG_TIMER) { - /* set conversion frequency */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd.convert_arg), - cmd. - flags & TRIG_ROUND_MASK); - if (das1800_set_frequency(dev) < 0) { - return -1; - } - } + if (cmd->convert_src == TRIG_TIMER) + size = (fill_time / cmd->convert_arg) * sample_size; break; - case TRIG_TIMER: /* in burst mode */ - /* set scan frequency */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd.scan_begin_arg), - cmd.flags & TRIG_ROUND_MASK); - if (das1800_set_frequency(dev) < 0) { - return -1; - } + case TRIG_TIMER: + size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) * + sample_size; break; default: + size = DMA_BUF_SIZE; break; } - /* setup counter 0 for 'about triggering' */ - if (cmd.stop_src == TRIG_EXT) { - /* load counter 0 in mode 0 */ - i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0); - } + /* set a minimum and maximum size allowed */ + max_size = DMA_BUF_SIZE; + /* if we are taking limited number of conversions, limit transfer size to that */ + if (cmd->stop_src == TRIG_COUNT && + cmd->stop_arg * cmd->chanlist_len * sample_size < max_size) + max_size = cmd->stop_arg * cmd->chanlist_len * sample_size; - return 0; + if (size > max_size) + size = max_size; + if (size < sample_size) + size = sample_size; + + return size; } /* sets up dma */ -static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd) +static void setup_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) { + struct das1800_private *devpriv = dev->private; unsigned long lock_flags; const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; @@ -1481,7 +1036,7 @@ static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd) return; /* determine a reasonable dma transfer size */ - devpriv->dma_transfer_size = suggest_transfer_size(&cmd); + devpriv->dma_transfer_size = suggest_transfer_size(cmd); lock_flags = claim_dma_lock(); disable_dma(devpriv->dma0); /* clear flip-flop to make sure 2-byte registers for @@ -1510,14 +1065,15 @@ static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd) } /* programs channel/gain list into card */ -static void program_chanlist(struct comedi_device *dev, struct comedi_cmd cmd) +static void program_chanlist(struct comedi_device *dev, + const struct comedi_cmd *cmd) { int i, n, chan_range; unsigned long irq_flags; const int range_mask = 0x3; /* masks unipolar/bipolar bit off range */ const int range_bitshift = 8; - n = cmd.chanlist_len; + n = cmd->chanlist_len; /* spinlock protects indirect addressing */ spin_lock_irqsave(&dev->spinlock, irq_flags); outb(QRAM, dev->iobase + DAS1800_SELECT); /* select QRAM for baseAddress + 0x0 */ @@ -1525,9 +1081,9 @@ static void program_chanlist(struct comedi_device *dev, struct comedi_cmd cmd) /* make channel / gain list */ for (i = 0; i < n; i++) { chan_range = - CR_CHAN(cmd. - chanlist[i]) | ((CR_RANGE(cmd.chanlist[i]) & - range_mask) << range_bitshift); + CR_CHAN(cmd->chanlist[i]) | + ((CR_RANGE(cmd->chanlist[i]) & range_mask) << + range_bitshift); outw(chan_range, dev->iobase + DAS1800_QRAM); } outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS); /*finish write to QRAM */ @@ -1540,26 +1096,19 @@ static void program_chanlist(struct comedi_device *dev, struct comedi_cmd cmd) static int das1800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - int ret; + struct das1800_private *devpriv = dev->private; int control_a, control_c; struct comedi_async *async = s->async; - struct comedi_cmd cmd = async->cmd; - - if (!dev->irq) { - comedi_error(dev, - "no irq assigned for das-1800, cannot do hardware conversions"); - return -1; - } + const struct comedi_cmd *cmd = &async->cmd; /* disable dma on TRIG_WAKE_EOS, or TRIG_RT * (because dma in handler is unsafe at hard real-time priority) */ - if (cmd.flags & (TRIG_WAKE_EOS | TRIG_RT)) { + if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) devpriv->irq_dma_bits &= ~DMA_ENABLED; - } else { + else devpriv->irq_dma_bits |= devpriv->dma_bits; - } /* interrupt on end of conversion for TRIG_WAKE_EOS */ - if (cmd.flags & TRIG_WAKE_EOS) { + if (cmd->flags & TRIG_WAKE_EOS) { /* interrupt fifo not empty */ devpriv->irq_dma_bits &= ~FIMD; } else { @@ -1567,9 +1116,8 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, devpriv->irq_dma_bits |= FIMD; } /* determine how many conversions we need */ - if (cmd.stop_src == TRIG_COUNT) { - devpriv->count = cmd.stop_arg * cmd.chanlist_len; - } + if (cmd->stop_src == TRIG_COUNT) + devpriv->count = cmd->stop_arg * cmd->chanlist_len; das1800_cancel(dev, s); @@ -1579,19 +1127,15 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, /* setup card and start */ program_chanlist(dev, cmd); - ret = setup_counters(dev, cmd); - if (ret < 0) { - comedi_error(dev, "Error setting up counters"); - return ret; - } + das1800_setup_counters(dev, cmd); setup_dma(dev, cmd); outb(control_c, dev->iobase + DAS1800_CONTROL_C); /* set conversion rate and length for burst mode */ if (control_c & BMDE) { /* program conversion period with number of microseconds minus 1 */ - outb(cmd.convert_arg / 1000 - 1, + outb(cmd->convert_arg / 1000 - 1, dev->iobase + DAS1800_BURST_RATE); - outb(cmd.chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH); + outb(cmd->chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH); } outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); /* enable irq/dma */ outb(control_a, dev->iobase + DAS1800_CONTROL_A); /* enable fifo and triggering */ @@ -1605,10 +1149,11 @@ 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); int i, n; int chan, range, aref, chan_range; int timeout = 1000; - short dpnt; + unsigned short dpnt; int conv_flags = 0; unsigned long irq_flags; @@ -1668,10 +1213,12 @@ 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); + struct das1800_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); /* int range = CR_RANGE(insn->chanspec); */ int update_chan = thisboard->ao_n_chan - 1; - short output; + unsigned short output; unsigned long irq_flags; /* card expects two's complement data */ @@ -1702,116 +1249,360 @@ static int das1800_di_rbits(struct comedi_device *dev, data[1] = inb(dev->iobase + DAS1800_DIGITAL) & 0xf; data[0] = 0; - return 2; + return insn->n; } -/* writes to digital output channels */ static int das1800_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int wbits; - - /* only set bits that have been masked */ - data[0] &= (1 << s->n_chan) - 1; - wbits = devpriv->do_bits; - wbits &= ~data[0]; - wbits |= data[0] & data[1]; - devpriv->do_bits = wbits; + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS1800_DIGITAL); - outb(devpriv->do_bits, dev->iobase + DAS1800_DIGITAL); + data[1] = s->state; - data[1] = devpriv->do_bits; - - return 2; + return insn->n; } -/* loads counters with divisor1, divisor2 from private structure */ -static int das1800_set_frequency(struct comedi_device *dev) +static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0, + unsigned int dma1) { - int err = 0; - - /* counter 1, mode 2 */ - if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 1, devpriv->divisor1, - 2)) - err++; - /* counter 2, mode 2 */ - if (i8254_load(dev->iobase + DAS1800_COUNTER, 0, 2, devpriv->divisor2, - 2)) - err++; - if (err) - return -1; + struct das1800_private *devpriv = dev->private; + unsigned long flags; + /* need an irq to do dma */ + if (dev->irq && dma0) { + /* encode dma0 and dma1 into 2 digit hexadecimal for switch */ + switch ((dma0 & 0x7) | (dma1 << 4)) { + case 0x5: /* dma0 == 5 */ + devpriv->dma_bits |= DMA_CH5; + break; + case 0x6: /* dma0 == 6 */ + devpriv->dma_bits |= DMA_CH6; + break; + case 0x7: /* dma0 == 7 */ + devpriv->dma_bits |= DMA_CH7; + break; + case 0x65: /* dma0 == 5, dma1 == 6 */ + devpriv->dma_bits |= DMA_CH5_CH6; + break; + case 0x76: /* dma0 == 6, dma1 == 7 */ + devpriv->dma_bits |= DMA_CH6_CH7; + break; + case 0x57: /* dma0 == 7, dma1 == 5 */ + devpriv->dma_bits |= DMA_CH7_CH5; + break; + default: + dev_err(dev->class_dev, + "only supports dma channels 5 through 7\n"); + dev_err(dev->class_dev, + "Dual dma only allows the following combinations:\n"); + dev_err(dev->class_dev, + "dma 5,6 / 6,7 / or 7,5\n"); + return -EINVAL; + break; + } + if (request_dma(dma0, dev->driver->driver_name)) { + dev_err(dev->class_dev, + "failed to allocate dma channel %i\n", dma0); + return -EINVAL; + } + devpriv->dma0 = dma0; + devpriv->dma_current = dma0; + if (dma1) { + if (request_dma(dma1, dev->driver->driver_name)) { + dev_err(dev->class_dev, + "failed to allocate dma channel %i\n", + dma1); + return -EINVAL; + } + devpriv->dma1 = dma1; + } + devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA); + if (devpriv->ai_buf0 == NULL) + return -ENOMEM; + devpriv->dma_current_buf = devpriv->ai_buf0; + if (dma1) { + devpriv->ai_buf1 = + kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA); + if (devpriv->ai_buf1 == NULL) + return -ENOMEM; + } + flags = claim_dma_lock(); + disable_dma(devpriv->dma0); + set_dma_mode(devpriv->dma0, DMA_MODE_READ); + if (dma1) { + disable_dma(devpriv->dma1); + set_dma_mode(devpriv->dma1, DMA_MODE_READ); + } + release_dma_lock(flags); + } return 0; } -/* converts requested conversion timing to timing compatible with - * hardware, used only when card is in 'burst mode' - */ -static unsigned int burst_convert_arg(unsigned int convert_arg, int round_mode) +static int das1800_probe(struct comedi_device *dev) { - unsigned int micro_sec; + int id; + int board; - /* in burst mode, the maximum conversion time is 64 microseconds */ - if (convert_arg > 64000) - convert_arg = 64000; + id = (inb(dev->iobase + DAS1800_DIGITAL) >> 4) & 0xf; /* get id bits */ + board = ((struct das1800_board *)dev->board_ptr) - das1800_boards; - /* the conversion time must be an integral number of microseconds */ - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - micro_sec = (convert_arg + 500) / 1000; + switch (id) { + case 0x3: + if (board == das1801st_da || board == das1802st_da || + board == das1701st_da || board == das1702st_da) { + dev_dbg(dev->class_dev, "Board model: %s\n", + das1800_boards[board].name); + return board; + } + printk + (" Board model (probed, not recommended): das-1800st-da series\n"); + return das1801st; break; - case TRIG_ROUND_DOWN: - micro_sec = convert_arg / 1000; + case 0x4: + if (board == das1802hr_da || board == das1702hr_da) { + dev_dbg(dev->class_dev, "Board model: %s\n", + das1800_boards[board].name); + return board; + } + printk + (" Board model (probed, not recommended): das-1802hr-da\n"); + return das1802hr; break; - case TRIG_ROUND_UP: - micro_sec = (convert_arg - 1) / 1000 + 1; + case 0x5: + if (board == das1801ao || board == das1802ao || + board == das1701ao || board == das1702ao) { + dev_dbg(dev->class_dev, "Board model: %s\n", + das1800_boards[board].name); + return board; + } + printk + (" Board model (probed, not recommended): das-1800ao series\n"); + return das1801ao; + break; + case 0x6: + if (board == das1802hr || board == das1702hr) { + dev_dbg(dev->class_dev, "Board model: %s\n", + das1800_boards[board].name); + return board; + } + printk + (" Board model (probed, not recommended): das-1802hr\n"); + return das1802hr; + break; + case 0x7: + if (board == das1801st || board == das1802st || + board == das1701st || board == das1702st) { + dev_dbg(dev->class_dev, "Board model: %s\n", + das1800_boards[board].name); + return board; + } + printk + (" Board model (probed, not recommended): das-1800st series\n"); + return das1801st; + break; + case 0x8: + if (board == das1801hc || board == das1802hc) { + dev_dbg(dev->class_dev, "Board model: %s\n", + das1800_boards[board].name); + return board; + } + printk + (" Board model (probed, not recommended): das-1800hc series\n"); + return das1801hc; + break; + default: + printk + (" Board model: probe returned 0x%x (unknown, please report)\n", + id); + return board; break; } - - /* return number of nanoseconds */ - return micro_sec * 1000; + return -1; } -/* utility function that suggests a dma transfer size based on the conversion period 'ns' */ -static unsigned int suggest_transfer_size(struct comedi_cmd *cmd) +static int das1800_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { - unsigned int size = DMA_BUF_SIZE; - static const int sample_size = 2; /* size in bytes of one sample from board */ - unsigned int fill_time = 300000000; /* target time in nanoseconds for filling dma buffer */ - unsigned int max_size; /* maximum size we will allow for a transfer */ + const struct das1800_board *thisboard; + struct das1800_private *devpriv; + struct comedi_subdevice *s; + unsigned int irq = it->options[1]; + unsigned int dma0 = it->options[2]; + unsigned int dma1 = it->options[3]; + int board; + int ret; - /* make dma buffer fill in 0.3 seconds for timed modes */ - switch (cmd->scan_begin_src) { - case TRIG_FOLLOW: /* not in burst mode */ - if (cmd->convert_src == TRIG_TIMER) - size = (fill_time / cmd->convert_arg) * sample_size; - break; - case TRIG_TIMER: - size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) * - sample_size; - break; - default: - size = DMA_BUF_SIZE; - break; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], DAS1800_SIZE); + if (ret) + return ret; + + board = das1800_probe(dev); + if (board < 0) { + dev_err(dev->class_dev, "unable to determine board type\n"); + return -ENODEV; } - /* set a minimum and maximum size allowed */ - max_size = DMA_BUF_SIZE; - /* if we are taking limited number of conversions, limit transfer size to that */ - if (cmd->stop_src == TRIG_COUNT && - cmd->stop_arg * cmd->chanlist_len * sample_size < max_size) - max_size = cmd->stop_arg * cmd->chanlist_len * sample_size; + dev->board_ptr = das1800_boards + board; + thisboard = comedi_board(dev); + dev->board_name = thisboard->name; - if (size > max_size) - size = max_size; - if (size < sample_size) - size = sample_size; + /* if it is an 'ao' board with fancy analog out then we need extra io ports */ + if (thisboard->ao_ability == 2) { + unsigned long iobase2 = dev->iobase + IOBASE2; - return size; + ret = __comedi_request_region(dev, iobase2, DAS1800_SIZE); + if (ret) + return ret; + devpriv->iobase2 = iobase2; + } + + if (irq == 3 || irq == 5 || irq == 7 || irq == 10 || irq == 11 || + irq == 15) { + ret = request_irq(irq, das1800_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = irq; + + switch (irq) { + case 3: + devpriv->irq_dma_bits |= 0x8; + break; + case 5: + devpriv->irq_dma_bits |= 0x10; + break; + case 7: + devpriv->irq_dma_bits |= 0x18; + break; + case 10: + devpriv->irq_dma_bits |= 0x28; + break; + case 11: + devpriv->irq_dma_bits |= 0x30; + break; + case 15: + devpriv->irq_dma_bits |= 0x38; + break; + } + } + } + + ret = das1800_init_dma(dev, dma0, dma1); + if (ret < 0) + return ret; + + if (devpriv->ai_buf0 == NULL) { + devpriv->ai_buf0 = + kmalloc(FIFO_SIZE * sizeof(uint16_t), GFP_KERNEL); + if (devpriv->ai_buf0 == NULL) + return -ENOMEM; + } + + 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_DIFF | SDF_GROUND; + if (thisboard->common) + s->subdev_flags |= SDF_COMMON; + s->n_chan = thisboard->qram_len; + s->maxdata = (1 << thisboard->resolution) - 1; + s->range_table = thisboard->range_ai; + s->insn_read = das1800_ai_rinsn; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmd = das1800_ai_do_cmd; + s->do_cmdtest = das1800_ai_do_cmdtest; + s->poll = das1800_ai_poll; + s->cancel = das1800_cancel; + } + + /* analog out */ + s = &dev->subdevices[1]; + if (thisboard->ao_ability == 1) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = thisboard->ao_n_chan; + s->maxdata = (1 << thisboard->resolution) - 1; + s->range_table = &range_bipolar10; + s->insn_write = das1800_ao_winsn; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* di */ + 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 = das1800_di_rbits; + + /* do */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = thisboard->do_n_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das1800_do_wbits; + + das1800_cancel(dev, dev->read_subdev); + + /* initialize digital out channels */ + outb(0, dev->iobase + DAS1800_DIGITAL); + + /* initialize analog out channels */ + if (thisboard->ao_ability == 1) { + /* select 'update' dac channel for baseAddress + 0x0 */ + outb(DAC(thisboard->ao_n_chan - 1), + dev->iobase + DAS1800_SELECT); + outw(devpriv->ao_update_bits, dev->iobase + DAS1800_DAC); + } + + return 0; +}; + +static void das1800_detach(struct comedi_device *dev) +{ + struct das1800_private *devpriv = dev->private; + + if (devpriv) { + if (devpriv->dma0) + free_dma(devpriv->dma0); + if (devpriv->dma1) + free_dma(devpriv->dma1); + kfree(devpriv->ai_buf0); + kfree(devpriv->ai_buf1); + if (devpriv->iobase2) + release_region(devpriv->iobase2, DAS1800_SIZE); + } + comedi_legacy_detach(dev); } +static struct comedi_driver das1800_driver = { + .driver_name = "das1800", + .module = THIS_MODULE, + .attach = das1800_attach, + .detach = das1800_detach, + .num_names = ARRAY_SIZE(das1800_boards), + .board_name = &das1800_boards[0].name, + .offset = sizeof(struct das1800_board), +}; +module_comedi_driver(das1800_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index 6328f5280b6..d18eea6c01a 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -1,377 +1,547 @@ /* - Some comments on the code.. - - - it shouldn't be necessary to use outb_p(). - - - ignoreirq creates a race condition. It needs to be fixed. - + * das6402.c + * Comedi driver for DAS6402 compatible boards + * Copyright(c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Rewrite of an experimental driver by: + * Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ /* - comedi/drivers/das6402.c - An experimental driver for Computerboards' DAS6402 I/O card - - Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. + * Driver: das6402 + * Description: Keithley Metrabyte DAS6402 (& compatibles) + * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12) + * (Keithley Metrabyte) DAS6402-16 (das6402-16) + * Author: H Hartley Sweeten <hsweeten@visionengravers.com> + * Updated: Fri, 14 Mar 2014 10:18:43 -0700 + * Status: unknown + * + * Configuration Options: + * [0] - I/O base address + * [1] - IRQ (optional, needed for async command support) + */ - 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> - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +#include "../comedidev.h" +#include "8253.h" +/* + * Register I/O map */ +#define DAS6402_AI_DATA_REG 0x00 +#define DAS6402_AI_MUX_REG 0x02 +#define DAS6402_AI_MUX_LO(x) (((x) & 0x3f) << 0) +#define DAS6402_AI_MUX_HI(x) (((x) & 0x3f) << 8) +#define DAS6402_DI_DO_REG 0x03 +#define DAS6402_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define DAS6402_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define DAS6402_STATUS_REG 0x08 +#define DAS6402_STATUS_FFNE (1 << 0) +#define DAS6402_STATUS_FHALF (1 << 1) +#define DAS6402_STATUS_FFULL (1 << 2) +#define DAS6402_STATUS_XINT (1 << 3) +#define DAS6402_STATUS_INT (1 << 4) +#define DAS6402_STATUS_XTRIG (1 << 5) +#define DAS6402_STATUS_INDGT (1 << 6) +#define DAS6402_STATUS_10MHZ (1 << 7) +#define DAS6402_STATUS_W_CLRINT (1 << 0) +#define DAS6402_STATUS_W_CLRXTR (1 << 1) +#define DAS6402_STATUS_W_CLRXIN (1 << 2) +#define DAS6402_STATUS_W_EXTEND (1 << 4) +#define DAS6402_STATUS_W_ARMED (1 << 5) +#define DAS6402_STATUS_W_POSTMODE (1 << 6) +#define DAS6402_STATUS_W_10MHZ (1 << 7) +#define DAS6402_CTRL_REG 0x09 +#define DAS6402_CTRL_SOFT_TRIG (0 << 0) +#define DAS6402_CTRL_EXT_FALL_TRIG (1 << 0) +#define DAS6402_CTRL_EXT_RISE_TRIG (2 << 0) +#define DAS6402_CTRL_PACER_TRIG (3 << 0) +#define DAS6402_CTRL_BURSTEN (1 << 2) +#define DAS6402_CTRL_XINTE (1 << 3) +#define DAS6402_CTRL_IRQ(x) ((x) << 4) +#define DAS6402_CTRL_INTE (1 << 7) +#define DAS6402_TRIG_REG 0x0a +#define DAS6402_TRIG_TGEN (1 << 0) +#define DAS6402_TRIG_TGSEL (1 << 1) +#define DAS6402_TRIG_TGPOL (1 << 2) +#define DAS6402_TRIG_PRETRIG (1 << 3) +#define DAS6402_AO_RANGE(_chan, _range) ((_range) << ((_chan) ? 6 : 4)) +#define DAS6402_AO_RANGE_MASK(_chan) (3 << ((_chan) ? 6 : 4)) +#define DAS6402_MODE_REG 0x0b +#define DAS6402_MODE_RANGE(x) ((x) << 0) +#define DAS6402_MODE_POLLED (0 << 2) +#define DAS6402_MODE_FIFONEPTY (1 << 2) +#define DAS6402_MODE_FIFOHFULL (2 << 2) +#define DAS6402_MODE_EOB (3 << 2) +#define DAS6402_MODE_ENHANCED (1 << 4) +#define DAS6402_MODE_SE (1 << 5) +#define DAS6402_MODE_UNI (1 << 6) +#define DAS6402_MODE_DMA1 (0 << 7) +#define DAS6402_MODE_DMA3 (1 << 7) +#define DAS6402_TIMER_BASE 0x0c + +static const struct comedi_lrange das6402_ai_ranges = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } +}; + /* -Driver: das6402 -Description: Keithley Metrabyte DAS6402 (& compatibles) -Author: Oystein Svendsen <svendsen@pvv.org> -Status: bitrotten -Devices: [Keithley Metrabyte] DAS6402 (das6402) + * Analog output ranges are programmable on the DAS6402/12. + * For the DAS6402/16 the range bits have no function, the + * DAC ranges are selected by switches on the board. + */ +static const struct comedi_lrange das6402_ao_ranges = { + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) + } +}; -This driver has suffered bitrot. -*/ +struct das6402_boardinfo { + const char *name; + unsigned int maxdata; +}; -#include <linux/interrupt.h> -#include "../comedidev.h" +static struct das6402_boardinfo das6402_boards[] = { + { + .name = "das6402-12", + .maxdata = 0x0fff, + }, { + .name = "das6402-16", + .maxdata = 0xffff, + }, +}; -#include <linux/ioport.h> - -#define DAS6402_SIZE 16 - -#define N_WORDS (3000*64) - -#define STOP 0 -#define START 1 - -#define SCANL 0x3f00 -#define BYTE unsigned char -#define WORD unsigned short - -/*----- register 8 ----*/ -#define CLRINT 0x01 -#define CLRXTR 0x02 -#define CLRXIN 0x04 -#define EXTEND 0x10 -#define ARMED 0x20 /* enable conting of post sample conv */ -#define POSTMODE 0x40 -#define MHZ 0x80 /* 10 MHz clock */ -/*---------------------*/ - -/*----- register 9 ----*/ -#define IRQ (0x04 << 4) /* these two are */ -#define IRQV 10 /* dependent on each other */ - -#define CONVSRC 0x03 /* trig src is Intarnal pacer */ -#define BURSTEN 0x04 /* enable burst */ -#define XINTE 0x08 /* use external int. trig */ -#define INTE 0x80 /* enable analog interrupts */ -/*---------------------*/ - -/*----- register 10 ---*/ -#define TGEN 0x01 /* Use pin DI1 for externl trigging? */ -#define TGSEL 0x02 /* Use edge triggering */ -#define TGPOL 0x04 /* active edge is falling */ -#define PRETRIG 0x08 /* pretrig */ -/*---------------------*/ - -/*----- register 11 ---*/ -#define EOB 0x0c -#define FIFOHFULL 0x08 -#define GAIN 0x01 -#define FIFONEPTY 0x04 -#define MODE 0x10 -#define SEM 0x20 -#define BIP 0x40 -/*---------------------*/ - -#define M0 0x00 -#define M2 0x04 - -#define C0 0x00 -#define C1 0x40 -#define C2 0x80 -#define RWLH 0x30 +struct das6402_private { + unsigned int irq; -static int das6402_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int das6402_detach(struct comedi_device *dev); -static struct comedi_driver driver_das6402 = { - .driver_name = "das6402", - .module = THIS_MODULE, - .attach = das6402_attach, - .detach = das6402_detach, + unsigned int count; + unsigned int divider1; + unsigned int divider2; + + unsigned int ao_range; + unsigned int ao_readback[2]; }; -static int __init driver_das6402_init_module(void) +static void das6402_set_mode(struct comedi_device *dev, + unsigned int mode) { - return comedi_driver_register(&driver_das6402); + outb(DAS6402_MODE_ENHANCED | mode, dev->iobase + DAS6402_MODE_REG); } -static void __exit driver_das6402_cleanup_module(void) +static void das6402_set_extended(struct comedi_device *dev, + unsigned int val) { - comedi_driver_unregister(&driver_das6402); + outb(DAS6402_STATUS_W_EXTEND, dev->iobase + DAS6402_STATUS_REG); + outb(DAS6402_STATUS_W_EXTEND | val, dev->iobase + DAS6402_STATUS_REG); + outb(val, dev->iobase + DAS6402_STATUS_REG); } -module_init(driver_das6402_init_module); -module_exit(driver_das6402_cleanup_module); - -struct das6402_private { - int ai_bytes_to_read; - - int das6402_ignoreirq; -}; -#define devpriv ((struct das6402_private *)dev->private) +static void das6402_clear_all_interrupts(struct comedi_device *dev) +{ + outb(DAS6402_STATUS_W_CLRINT | + DAS6402_STATUS_W_CLRXTR | + DAS6402_STATUS_W_CLRXIN, dev->iobase + DAS6402_STATUS_REG); +} -static void das6402_ai_fifo_dregs(struct comedi_device *dev, - struct comedi_subdevice *s); +static void das6402_ai_clear_eoc(struct comedi_device *dev) +{ + outb(DAS6402_STATUS_W_CLRINT, dev->iobase + DAS6402_STATUS_REG); +} -static void das6402_setcounter(struct comedi_device *dev) +static void das6402_enable_counter(struct comedi_device *dev, bool load) { - BYTE p; - unsigned short ctrlwrd; - - /* set up counter0 first, mode 0 */ - p = M0 | C0 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 2000; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 12); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 12); - - /* set up counter1, mode 2 */ - p = M2 | C1 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 10; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 13); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 13); - - /* set up counter1, mode 2 */ - p = M2 | C2 | RWLH; - outb_p(p, dev->iobase + 15); - ctrlwrd = 1000; - p = (BYTE) (0xff & ctrlwrd); - outb_p(p, dev->iobase + 14); - p = (BYTE) (0xff & (ctrlwrd >> 8)); - outb_p(p, dev->iobase + 14); + struct das6402_private *devpriv = dev->private; + unsigned long timer_iobase = dev->iobase + DAS6402_TIMER_BASE; + + if (load) { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_iobase, 0, 0, devpriv->count); + i8254_write(timer_iobase, 0, 1, devpriv->divider1); + i8254_write(timer_iobase, 0, 2, devpriv->divider2); + + } else { + i8254_set_mode(timer_iobase, 0, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_iobase, 0, 2, I8254_MODE0 | I8254_BINARY); + } } -static irqreturn_t intr_handler(int irq, void *d) +static irqreturn_t das6402_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices; - - if (!dev->attached || devpriv->das6402_ignoreirq) { - printk("das6402: BUG: spurious interrupt\n"); - return IRQ_HANDLED; - } -#ifdef DEBUG - printk("das6402: interrupt! das6402_irqcount=%i\n", - devpriv->das6402_irqcount); - printk("das6402: iobase+2=%i\n", inw_p(dev->iobase + 2)); -#endif - - das6402_ai_fifo_dregs(dev, s); - - if (s->async->buf_write_count >= devpriv->ai_bytes_to_read) { - outw_p(SCANL, dev->iobase + 2); /* clears the fifo */ - outb(0x07, dev->iobase + 8); /* clears all flip-flops */ -#ifdef DEBUG - printk("das6402: Got %i samples\n\n", - devpriv->das6402_wordsread - diff); -#endif - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - } - outb(0x01, dev->iobase + 8); /* clear only the interrupt flip-flop */ + das6402_clear_all_interrupts(dev); - comedi_event(dev, s); return IRQ_HANDLED; } -#if 0 -static void das6402_ai_fifo_read(struct comedi_device *dev, short *data, int n) +static int das6402_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { - int i; - - for (i = 0; i < n; i++) - data[i] = inw(dev->iobase); + return -EINVAL; } -#endif -static void das6402_ai_fifo_dregs(struct comedi_device *dev, - struct comedi_subdevice *s) +static int das6402_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - while (1) { - if (!(inb(dev->iobase + 8) & 0x01)) - return; - comedi_buf_put(s->async, inw(dev->iobase)); - } + return -EINVAL; } static int das6402_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - /* - * This function should reset the board from whatever condition it - * is in (i.e., acquiring data), to a non-active state. - */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + return 0; +} - devpriv->das6402_ignoreirq = 1; -#ifdef DEBUG - printk("das6402: Stopping acquisition\n"); -#endif - devpriv->das6402_ignoreirq = 1; - outb_p(0x02, dev->iobase + 10); /* disable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(0, dev->iobase + 9); /* disables interrupts */ +static void das6402_ai_soft_trig(struct comedi_device *dev) +{ + outw(0, dev->iobase + DAS6402_AI_DATA_REG); +} - outw_p(SCANL, dev->iobase + 2); +static int das6402_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; - return 0; + status = inb(dev->iobase + DAS6402_STATUS_REG); + if (status & DAS6402_STATUS_FFNE) + return 0; + return -EBUSY; } -#ifdef unused -static int das6402_ai_mode2(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig * it) +static int das6402_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - devpriv->das6402_ignoreirq = 1; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned int val; + int ret; + int i; -#ifdef DEBUG - printk("das6402: Starting acquisition\n"); -#endif - outb_p(0x03, dev->iobase + 10); /* enable external trigging */ - outw_p(SCANL, dev->iobase + 2); /* resets the card fifo */ - outb_p(IRQ | CONVSRC | BURSTEN | INTE, dev->iobase + 9); + val = DAS6402_MODE_RANGE(range) | DAS6402_MODE_POLLED; + if (aref == AREF_DIFF) { + if (chan > s->n_chan / 2) + return -EINVAL; + } else { + val |= DAS6402_MODE_SE; + } + if (comedi_range_is_unipolar(s, range)) + val |= DAS6402_MODE_UNI; - devpriv->ai_bytes_to_read = it->n * sizeof(short); + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); - /* um... ignoreirq is a nasty race condition */ - devpriv->das6402_ignoreirq = 0; + das6402_set_mode(dev, val); - outw_p(SCANL, dev->iobase + 2); + /* load the mux for single channel conversion */ + outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan), + dev->iobase + DAS6402_AI_MUX_REG); - return 0; + for (i = 0; i < insn->n; i++) { + das6402_ai_clear_eoc(dev); + das6402_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0); + if (ret) + break; + + val = inw(dev->iobase + DAS6402_AI_DATA_REG); + + if (s->maxdata == 0x0fff) + val >>= 4; + + data[i] = val; + } + + das6402_ai_clear_eoc(dev); + + return insn->n; } -#endif -static int board_init(struct comedi_device *dev) +static int das6402_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - BYTE b; + struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int i; - devpriv->das6402_ignoreirq = 1; + /* set the range for this channel */ + val = devpriv->ao_range; + val &= ~DAS6402_AO_RANGE_MASK(chan); + val |= DAS6402_AO_RANGE(chan, range); + if (val != devpriv->ao_range) { + devpriv->ao_range = val; + outb(val, dev->iobase + DAS6402_TRIG_REG); + } - outb(0x07, dev->iobase + 8); + /* + * The DAS6402/16 has a jumper to select either individual + * update (UPDATE) or simultaneous updating (XFER) of both + * DAC's. In UPDATE mode, when the MSB is written, that DAC + * is updated. In XFER mode, after both DAC's are loaded, + * a read cycle of any DAC register will update both DAC's + * simultaneously. + * + * If you have XFER mode enabled a (*insn_read) will need + * to be performed in order to update the DAC's with the + * last value written. + */ + for (i = 0; i < insn->n; i++) { + val = data[i]; + + devpriv->ao_readback[chan] = val; + + if (s->maxdata == 0x0fff) { + /* + * DAS6402/12 has the two 8-bit DAC registers, left + * justified (the 4 LSB bits are don't care). Data + * can be written as one word. + */ + val <<= 4; + outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan)); + } else { + /* + * DAS6402/16 uses both 8-bit DAC registers and needs + * to be written LSB then MSB. + */ + outb(val & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, + dev->iobase + DAS6402_AO_LSB_REG(chan)); + } + } + + return insn->n; +} - /* register 11 */ - outb_p(MODE, dev->iobase + 11); - b = BIP | SEM | MODE | GAIN | FIFOHFULL; - outb_p(b, dev->iobase + 11); +static int das6402_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct das6402_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - /* register 8 */ - outb_p(EXTEND, dev->iobase + 8); - b = EXTEND | MHZ; - outb_p(b, dev->iobase + 8); - b = MHZ | CLRINT | CLRXTR | CLRXIN; - outb_p(b, dev->iobase + 8); + /* + * If XFER mode is enabled, reading any DAC register + * will update both DAC's simultaneously. + */ + inw(dev->iobase + DAS6402_AO_LSB_REG(chan)); - /* register 9 */ - b = IRQ | CONVSRC | BURSTEN | INTE; - outb_p(b, dev->iobase + 9); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - /* register 10 */ - b = TGSEL | TGEN; - outb_p(b, dev->iobase + 10); + return insn->n; +} - b = 0x07; - outb_p(b, dev->iobase + 8); +static int das6402_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + DAS6402_DI_DO_REG); - das6402_setcounter(dev); + return insn->n; +} - outw_p(SCANL, dev->iobase + 2); /* reset card fifo */ +static int das6402_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAS6402_DI_DO_REG); - devpriv->das6402_ignoreirq = 0; + data[1] = s->state; - return 0; + return insn->n; } -static int das6402_detach(struct comedi_device *dev) +static void das6402_reset(struct comedi_device *dev) { - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, DAS6402_SIZE); + struct das6402_private *devpriv = dev->private; - return 0; + /* enable "Enhanced" mode */ + outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG); + + /* enable 10MHz pacer clock */ + das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ); + + /* enable software conversion trigger */ + outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG); + + /* default ADC to single-ended unipolar 10V inputs */ + das6402_set_mode(dev, DAS6402_MODE_RANGE(0) | + DAS6402_MODE_POLLED | + DAS6402_MODE_SE | + DAS6402_MODE_UNI); + + /* default mux for single channel conversion (channel 0) */ + outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0), + dev->iobase + DAS6402_AI_MUX_REG); + + /* set both DAC's for unipolar 5V output range */ + devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2); + outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG); + + /* set both DAC's to 0V */ + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + outw(0, dev->iobase + DAS6402_AO_DATA_REG(0)); + inw(dev->iobase + DAS6402_AO_LSB_REG(0)); + + das6402_enable_counter(dev, false); + + /* set all digital outputs low */ + outb(0, dev->iobase + DAS6402_DI_DO_REG); + + das6402_clear_all_interrupts(dev); } static int das6402_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - unsigned int irq; - unsigned long iobase; - int ret; + const struct das6402_boardinfo *board = comedi_board(dev); + struct das6402_private *devpriv; struct comedi_subdevice *s; + int ret; - dev->board_name = "das6402"; - - iobase = it->options[0]; - if (iobase == 0) - iobase = 0x300; - - printk("comedi%d: das6402: 0x%04lx", dev->minor, iobase); - - if (!request_region(iobase, DAS6402_SIZE, "das6402")) { - printk(" I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - /* should do a probe here */ + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - irq = it->options[0]; - printk(" ( irq = %u )", irq); - ret = request_irq(irq, intr_handler, 0, "das6402", dev); - if (ret < 0) { - printk("irq conflict\n"); + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) return ret; - } - dev->irq = irq; - ret = alloc_private(dev, sizeof(struct das6402_private)); - if (ret < 0) - return ret; + das6402_reset(dev); + + /* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */ + if ((1 << it->options[1]) & 0x8cec) { + ret = request_irq(it->options[1], das6402_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = it->options[1]; + + switch (dev->irq) { + case 10: + devpriv->irq = 4; + break; + case 11: + devpriv->irq = 1; + break; + case 15: + devpriv->irq = 6; + break; + default: + devpriv->irq = dev->irq; + break; + } + } + } - ret = alloc_subdevices(dev, 1); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - /* ai subdevice */ - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 8; - /* s->trig[2]=das6402_ai_mode2; */ - s->cancel = das6402_ai_cancel; - s->maxdata = (1 << 12) - 1; - s->len_chanlist = 16; /* ? */ - s->range_table = &range_unknown; + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 64; + s->maxdata = board->maxdata; + s->range_table = &das6402_ai_ranges; + s->insn_read = das6402_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = das6402_ai_cmdtest; + s->do_cmd = das6402_ai_cmd; + s->cancel = das6402_ai_cancel; + } - board_init(dev); + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = board->maxdata; + s->range_table = &das6402_ao_ranges; + s->insn_write = das6402_ao_insn_write; + s->insn_read = das6402_ao_insn_read; + + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_di_insn_bits; + + /* Digital Input subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das6402_do_insn_bits; return 0; } -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +static struct comedi_driver das6402_driver = { + .driver_name = "das6402", + .module = THIS_MODULE, + .attach = das6402_attach, + .detach = comedi_legacy_detach, + .board_name = &das6402_boards[0].name, + .num_names = ARRAY_SIZE(das6402_boards), + .offset = sizeof(struct das6402_boardinfo), +}; +module_comedi_driver(das6402_driver) + +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index 96d41ad7695..6f7f8d531dd 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -15,12 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: das800 @@ -62,17 +56,16 @@ cmd triggers supported: */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/delay.h> #include "8253.h" #include "comedi_fc.h" #define DAS800_SIZE 8 -#define TIMER_BASE 1000 #define N_CHAN_AI 8 /* number of analog input channels */ /* Registers for the das800 */ @@ -95,8 +88,8 @@ cmd triggers supported: #define IRQ 0x8 #define BUSY 0x80 #define DAS800_GAIN 3 -#define CIO_FFOV 0x8 /* fifo overflow for cio-das802/16 */ -#define CIO_ENHF 0x90 /* interrupt fifo half full for cio-das802/16 */ +#define CIO_FFOV 0x8 /* cio-das802/16 fifo overflow */ +#define CIO_ENHF 0x90 /* cio-das802/16 fifo half full int ena */ #define CONTROL1 0x80 #define CONV_CONTROL 0xa0 #define SCAN_LIMITS 0xc0 @@ -107,6 +100,8 @@ cmd triggers supported: #define STATUS2_INTE 0X20 #define DAS800_ID 7 +#define DAS802_16_HALF_FIFO_SZ 128 + struct das800_board { const char *name; int ai_speed; @@ -114,574 +109,265 @@ struct das800_board { int resolution; }; -/* analog input ranges */ -static const struct comedi_lrange range_das800_ai = { - 1, - { - RANGE(-5, 5), - } -}; - static const struct comedi_lrange range_das801_ai = { - 9, - { - RANGE(-5, 5), - RANGE(-10, 10), - RANGE(0, 10), - RANGE(-0.5, 0.5), - RANGE(0, 1), - RANGE(-0.05, 0.05), - RANGE(0, 0.1), - RANGE(-0.01, 0.01), - RANGE(0, 0.02), - } + 9, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(10), + BIP_RANGE(0.5), + UNI_RANGE(1), + BIP_RANGE(0.05), + UNI_RANGE(0.1), + BIP_RANGE(0.01), + UNI_RANGE(0.02) + } }; static const struct comedi_lrange range_cio_das801_ai = { - 9, - { - RANGE(-5, 5), - RANGE(-10, 10), - RANGE(0, 10), - RANGE(-0.5, 0.5), - RANGE(0, 1), - RANGE(-0.05, 0.05), - RANGE(0, 0.1), - RANGE(-0.005, 0.005), - RANGE(0, 0.01), - } + 9, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(10), + BIP_RANGE(0.5), + UNI_RANGE(1), + BIP_RANGE(0.05), + UNI_RANGE(0.1), + BIP_RANGE(0.005), + UNI_RANGE(0.01) + } }; static const struct comedi_lrange range_das802_ai = { - 9, - { - RANGE(-5, 5), - RANGE(-10, 10), - RANGE(0, 10), - RANGE(-2.5, 2.5), - RANGE(0, 5), - RANGE(-1.25, 1.25), - RANGE(0, 2.5), - RANGE(-0.625, 0.625), - RANGE(0, 1.25), - } + 9, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(10), + BIP_RANGE(2.5), + UNI_RANGE(5), + BIP_RANGE(1.25), + UNI_RANGE(2.5), + BIP_RANGE(0.625), + UNI_RANGE(1.25) + } }; static const struct comedi_lrange range_das80216_ai = { - 8, - { - RANGE(-10, 10), - RANGE(0, 10), - RANGE(-5, 5), - RANGE(0, 5), - RANGE(-2.5, 2.5), - RANGE(0, 2.5), - RANGE(-1.25, 1.25), - RANGE(0, 1.25), - } + 8, { + BIP_RANGE(10), + UNI_RANGE(10), + BIP_RANGE(5), + UNI_RANGE(5), + BIP_RANGE(2.5), + UNI_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(1.25) + } }; -enum { das800, ciodas800, das801, ciodas801, das802, ciodas802, ciodas80216 }; +enum das800_boardinfo { + BOARD_DAS800, + BOARD_CIODAS800, + BOARD_DAS801, + BOARD_CIODAS801, + BOARD_DAS802, + BOARD_CIODAS802, + BOARD_CIODAS80216, +}; static const struct das800_board das800_boards[] = { - { - .name = "das-800", - .ai_speed = 25000, - .ai_range = &range_das800_ai, - .resolution = 12, - }, - { - .name = "cio-das800", - .ai_speed = 20000, - .ai_range = &range_das800_ai, - .resolution = 12, - }, - { - .name = "das-801", - .ai_speed = 25000, - .ai_range = &range_das801_ai, - .resolution = 12, - }, - { - .name = "cio-das801", - .ai_speed = 20000, - .ai_range = &range_cio_das801_ai, - .resolution = 12, - }, - { - .name = "das-802", - .ai_speed = 25000, - .ai_range = &range_das802_ai, - .resolution = 12, - }, - { - .name = "cio-das802", - .ai_speed = 20000, - .ai_range = &range_das802_ai, - .resolution = 12, - }, - { - .name = "cio-das802/16", - .ai_speed = 10000, - .ai_range = &range_das80216_ai, - .resolution = 16, - }, + [BOARD_DAS800] = { + .name = "das-800", + .ai_speed = 25000, + .ai_range = &range_bipolar5, + .resolution = 12, + }, + [BOARD_CIODAS800] = { + .name = "cio-das800", + .ai_speed = 20000, + .ai_range = &range_bipolar5, + .resolution = 12, + }, + [BOARD_DAS801] = { + .name = "das-801", + .ai_speed = 25000, + .ai_range = &range_das801_ai, + .resolution = 12, + }, + [BOARD_CIODAS801] = { + .name = "cio-das801", + .ai_speed = 20000, + .ai_range = &range_cio_das801_ai, + .resolution = 12, + }, + [BOARD_DAS802] = { + .name = "das-802", + .ai_speed = 25000, + .ai_range = &range_das802_ai, + .resolution = 12, + }, + [BOARD_CIODAS802] = { + .name = "cio-das802", + .ai_speed = 20000, + .ai_range = &range_das802_ai, + .resolution = 12, + }, + [BOARD_CIODAS80216] = { + .name = "cio-das802/16", + .ai_speed = 10000, + .ai_range = &range_das80216_ai, + .resolution = 16, + }, }; -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct das800_board *)dev->board_ptr) - struct das800_private { - volatile unsigned int count; /* number of data points left to be taken */ - volatile int forever; /* flag indicating whether we should take data forever */ - unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */ - unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */ - volatile int do_bits; /* digital output bits */ -}; - -#define devpriv ((struct das800_private *)dev->private) - -static int das800_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int das800_detach(struct comedi_device *dev); -static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s); - -static struct comedi_driver driver_das800 = { - .driver_name = "das800", - .module = THIS_MODULE, - .attach = das800_attach, - .detach = das800_detach, - .num_names = ARRAY_SIZE(das800_boards), - .board_name = &das800_boards[0].name, - .offset = sizeof(struct das800_board), + unsigned int count; /* number of data points left to be taken */ + unsigned int divisor1; /* counter 1 value for timed conversions */ + unsigned int divisor2; /* counter 2 value for timed conversions */ + unsigned int do_bits; /* digital output bits */ }; -static irqreturn_t das800_interrupt(int irq, void *d); -static void enable_das800(struct comedi_device *dev); -static void disable_das800(struct comedi_device *dev); -static int das800_ai_do_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int das800_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int das800_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int das800_di_rbits(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int das800_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int das800_probe(struct comedi_device *dev); -static int das800_set_frequency(struct comedi_device *dev); - -/* checks and probes das-800 series board type */ -static int das800_probe(struct comedi_device *dev) +static void das800_ind_write(struct comedi_device *dev, + unsigned val, unsigned reg) { - int id_bits; - unsigned long irq_flags; - int board; - - /* 'comedi spin lock irqsave' disables even rt interrupts, we use them to protect indirect addressing */ - spin_lock_irqsave(&dev->spinlock, irq_flags); - outb(ID, dev->iobase + DAS800_GAIN); /* select base address + 7 to be ID register */ - id_bits = inb(dev->iobase + DAS800_ID) & 0x3; /* get id bits */ - spin_unlock_irqrestore(&dev->spinlock, irq_flags); - - board = thisboard - das800_boards; - - switch (id_bits) { - case 0x0: - if (board == das800) { - printk(" Board model: DAS-800\n"); - return board; - } - if (board == ciodas800) { - printk(" Board model: CIO-DAS800\n"); - return board; - } - printk(" Board model (probed): DAS-800\n"); - return das800; - break; - case 0x2: - if (board == das801) { - printk(" Board model: DAS-801\n"); - return board; - } - if (board == ciodas801) { - printk(" Board model: CIO-DAS801\n"); - return board; - } - printk(" Board model (probed): DAS-801\n"); - return das801; - break; - case 0x3: - if (board == das802) { - printk(" Board model: DAS-802\n"); - return board; - } - if (board == ciodas802) { - printk(" Board model: CIO-DAS802\n"); - return board; - } - if (board == ciodas80216) { - printk(" Board model: CIO-DAS802/16\n"); - return board; - } - printk(" Board model (probed): DAS-802\n"); - return das802; - break; - default: - printk(" Board model: probe returned 0x%x (unknown)\n", - id_bits); - return board; - break; - } - return -1; -} - -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_das800_init_module(void) -{ - return comedi_driver_register(&driver_das800); + /* + * Select dev->iobase + 2 to be desired register + * then write to that register. + */ + outb(reg, dev->iobase + DAS800_GAIN); + outb(val, dev->iobase + 2); } -static void __exit driver_das800_cleanup_module(void) +static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg) { - comedi_driver_unregister(&driver_das800); + /* + * Select dev->iobase + 7 to be desired register + * then read from that register. + */ + outb(reg, dev->iobase + DAS800_GAIN); + return inb(dev->iobase + 7); } -module_init(driver_das800_init_module); -module_exit(driver_das800_cleanup_module); - -/* interrupt service routine */ -static irqreturn_t das800_interrupt(int irq, void *d) +static void das800_enable(struct comedi_device *dev) { - short i; /* loop index */ - short dataPoint = 0; - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->read_subdev; /* analog input subdevice */ - struct comedi_async *async; - int status; + const struct das800_board *thisboard = comedi_board(dev); + struct das800_private *devpriv = dev->private; unsigned long irq_flags; - static const int max_loops = 128; /* half-fifo size for cio-das802/16 */ - /* flags */ - int fifo_empty = 0; - int fifo_overflow = 0; - status = inb(dev->iobase + DAS800_STATUS); - /* if interrupt was not generated by board or driver not attached, quit */ - if (!(status & IRQ)) - return IRQ_NONE; - if (!(dev->attached)) - return IRQ_HANDLED; - - /* wait until here to initialize async, since we will get null dereference - * if interrupt occurs before driver is fully attached! - */ - async = s->async; - - /* if hardware conversions are not enabled, then quit */ spin_lock_irqsave(&dev->spinlock, irq_flags); - outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select base address + 7 to be STATUS2 register */ - status = inb(dev->iobase + DAS800_STATUS2) & STATUS2_HCEN; - /* don't release spinlock yet since we want to make sure no one else disables hardware conversions */ - if (status == 0) { - spin_unlock_irqrestore(&dev->spinlock, irq_flags); - return IRQ_HANDLED; - } - - /* loop while card's fifo is not empty (and limit to half fifo for cio-das802/16) */ - for (i = 0; i < max_loops; i++) { - /* read 16 bits from dev->iobase and dev->iobase + 1 */ - dataPoint = inb(dev->iobase + DAS800_LSB); - dataPoint += inb(dev->iobase + DAS800_MSB) << 8; - if (thisboard->resolution == 12) { - fifo_empty = dataPoint & FIFO_EMPTY; - fifo_overflow = dataPoint & FIFO_OVF; - if (fifo_overflow) - break; - } else { - fifo_empty = 0; /* cio-das802/16 has no fifo empty status bit */ - } - if (fifo_empty) - break; - /* strip off extraneous bits for 12 bit cards */ - if (thisboard->resolution == 12) - dataPoint = (dataPoint >> 4) & 0xfff; - /* if there are more data points to collect */ - if (devpriv->count > 0 || devpriv->forever == 1) { - /* write data point to buffer */ - cfc_write_to_buffer(s, dataPoint); - if (devpriv->count > 0) - devpriv->count--; - } - } - async->events |= COMEDI_CB_BLOCK; - /* check for fifo overflow */ - if (thisboard->resolution == 12) { - fifo_overflow = dataPoint & FIFO_OVF; - /* else cio-das802/16 */ - } else { - fifo_overflow = inb(dev->iobase + DAS800_GAIN) & CIO_FFOV; - } - if (fifo_overflow) { - spin_unlock_irqrestore(&dev->spinlock, irq_flags); - comedi_error(dev, "DAS800 FIFO overflow"); - das800_cancel(dev, dev->subdevices + 0); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); - async->events = 0; - return IRQ_HANDLED; - } - if (devpriv->count > 0 || devpriv->forever == 1) { - /* Re-enable card's interrupt. - * We already have spinlock, so indirect addressing is safe */ - outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ - outb(CONTROL1_INTE | devpriv->do_bits, - dev->iobase + DAS800_CONTROL1); - spin_unlock_irqrestore(&dev->spinlock, irq_flags); - /* otherwise, stop taking data */ - } else { - spin_unlock_irqrestore(&dev->spinlock, irq_flags); - disable_das800(dev); /* diable hardware triggered conversions */ - async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); - async->events = 0; - return IRQ_HANDLED; + /* enable fifo-half full interrupts for cio-das802/16 */ + if (thisboard->resolution == 16) + outb(CIO_ENHF, dev->iobase + DAS800_GAIN); + /* enable hardware triggering */ + das800_ind_write(dev, CONV_HCEN, CONV_CONTROL); + /* enable card's interrupt */ + das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); } -static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static void das800_disable(struct comedi_device *dev) { - struct comedi_subdevice *s; - unsigned long iobase = it->options[0]; - unsigned int irq = it->options[1]; unsigned long irq_flags; - int board; - - printk("comedi%d: das800: io 0x%lx", dev->minor, iobase); - if (irq) - printk(", irq %u", irq); - printk("\n"); - - /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(struct das800_private)) < 0) - return -ENOMEM; - - if (iobase == 0) { - printk("io base address required for das800\n"); - return -EINVAL; - } - - /* check if io addresses are available */ - if (!request_region(iobase, DAS800_SIZE, "das800")) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - board = das800_probe(dev); - if (board < 0) { - printk("unable to determine board type\n"); - return -ENODEV; - } - dev->board_ptr = das800_boards + board; - - /* grab our IRQ */ - if (irq == 1 || irq > 7) { - printk("irq out of range\n"); - return -EINVAL; - } - if (irq) { - if (request_irq(irq, das800_interrupt, 0, "das800", dev)) { - printk("unable to allocate irq %u\n", irq); - return -EINVAL; - } - } - dev->irq = irq; - - dev->board_name = thisboard->name; - - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; - /* analog input subdevice */ - s = dev->subdevices + 0; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - s->n_chan = 8; - s->len_chanlist = 8; - s->maxdata = (1 << thisboard->resolution) - 1; - s->range_table = thisboard->ai_range; - s->do_cmd = das800_ai_do_cmd; - s->do_cmdtest = das800_ai_do_cmdtest; - s->insn_read = das800_ai_rinsn; - s->cancel = das800_cancel; - - /* di */ - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 3; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = das800_di_rbits; - - /* do */ - s = dev->subdevices + 2; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 4; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = das800_do_wbits; - - disable_das800(dev); - - /* initialize digital out channels */ spin_lock_irqsave(&dev->spinlock, irq_flags); - outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ - outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); + /* disable hardware triggering of conversions */ + das800_ind_write(dev, 0x0, CONV_CONTROL); spin_unlock_irqrestore(&dev->spinlock, irq_flags); +} - return 0; -}; - -static int das800_detach(struct comedi_device *dev) +static void das800_set_frequency(struct comedi_device *dev) { - printk("comedi%d: das800: remove\n", dev->minor); + struct das800_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + DAS800_8254; - /* only free stuff if it has been allocated by _attach */ - if (dev->iobase) - release_region(dev->iobase, DAS800_SIZE); - if (dev->irq) - free_irq(dev->irq, dev); - return 0; -}; + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); +} static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - devpriv->forever = 0; + struct das800_private *devpriv = dev->private; + devpriv->count = 0; - disable_das800(dev); + das800_disable(dev); return 0; } -/* enable_das800 makes the card start taking hardware triggered conversions */ -static void enable_das800(struct comedi_device *dev) +static int das800_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - unsigned long irq_flags; - spin_lock_irqsave(&dev->spinlock, irq_flags); - /* enable fifo-half full interrupts for cio-das802/16 */ - if (thisboard->resolution == 16) - outb(CIO_ENHF, dev->iobase + DAS800_GAIN); - outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ - outb(CONV_HCEN, dev->iobase + DAS800_CONV_CONTROL); /* enable hardware triggering */ - outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ - outb(CONTROL1_INTE | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); /* enable card's interrupt */ - spin_unlock_irqrestore(&dev->spinlock, irq_flags); -} + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; -/* disable_das800 stops hardware triggered conversions */ -static void disable_das800(struct comedi_device *dev) -{ - unsigned long irq_flags; - spin_lock_irqsave(&dev->spinlock, irq_flags); - outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ - outb(0x0, dev->iobase + DAS800_CONV_CONTROL); /* disable hardware triggering of conversions */ - spin_unlock_irqrestore(&dev->spinlock, irq_flags); + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "chanlist must be consecutive, counting upwards\n"); + return -EINVAL; + } + + if (range != range0) { + dev_dbg(dev->class_dev, + "chanlist must all have the same gain\n"); + return -EINVAL; + } + } + + return 0; } static int das800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct das800_board *thisboard = comedi_board(dev); + struct das800_private *devpriv = dev->private; int err = 0; - int tmp; - int gain, startChan; - int i; + unsigned int arg; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + 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); - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + if (err) + return 1; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 2a : make sure trigger sources are unique */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + /* Step 2b : and mutually compatible */ if (err) - return 1; + return 2; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (err) - return 2; + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + thisboard->ai_speed); - /* step 3: make sure arguments are trivially compatible */ + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < thisboard->ai_speed) { - cmd->convert_arg = thisboard->ai_speed; - err++; - } - } - if (!cmd->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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; @@ -689,37 +375,20 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - /* calculate counter values that give desired timing */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd->convert_arg), - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_1MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - startChan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (startChan + i) % N_CHAN_AI) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= das800_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -730,192 +399,372 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, static int das800_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - int startChan, endChan, scan, gain; + const struct das800_board *thisboard = comedi_board(dev); + struct das800_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int gain = CR_RANGE(cmd->chanlist[0]); + unsigned int start_chan = CR_CHAN(cmd->chanlist[0]); + unsigned int end_chan = (start_chan + cmd->chanlist_len - 1) % 8; + unsigned int scan_chans = (end_chan << 3) | start_chan; int conv_bits; unsigned long irq_flags; - struct comedi_async *async = s->async; - - if (!dev->irq) { - comedi_error(dev, - "no irq assigned for das-800, cannot do hardware conversions"); - return -1; - } - disable_das800(dev); - - /* set channel scan limits */ - startChan = CR_CHAN(async->cmd.chanlist[0]); - endChan = (startChan + async->cmd.chanlist_len - 1) % 8; - scan = (endChan << 3) | startChan; + das800_disable(dev); spin_lock_irqsave(&dev->spinlock, irq_flags); - outb(SCAN_LIMITS, dev->iobase + DAS800_GAIN); /* select base address + 2 to be scan limits register */ - outb(scan, dev->iobase + DAS800_SCAN_LIMITS); /* set scan limits */ + /* set scan limits */ + das800_ind_write(dev, scan_chans, SCAN_LIMITS); spin_unlock_irqrestore(&dev->spinlock, irq_flags); /* set gain */ - gain = CR_RANGE(async->cmd.chanlist[0]); if (thisboard->resolution == 12 && gain > 0) gain += 0x7; gain &= 0xf; outb(gain, dev->iobase + DAS800_GAIN); - switch (async->cmd.stop_src) { - case TRIG_COUNT: - devpriv->count = async->cmd.stop_arg * async->cmd.chanlist_len; - devpriv->forever = 0; - break; - case TRIG_NONE: - devpriv->forever = 1; + if (cmd->stop_src == TRIG_COUNT) + devpriv->count = cmd->stop_arg * cmd->chanlist_len; + else /* TRIG_NONE */ devpriv->count = 0; - break; - default: - break; - } /* enable auto channel scan, send interrupts on end of conversion * and set clock source to internal or external */ conv_bits = 0; conv_bits |= EACS | IEOC; - if (async->cmd.start_src == TRIG_EXT) + if (cmd->start_src == TRIG_EXT) conv_bits |= DTEN; - switch (async->cmd.convert_src) { - case TRIG_TIMER: + if (cmd->convert_src == TRIG_TIMER) { conv_bits |= CASC | ITE; /* set conversion frequency */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), - &(devpriv->divisor2), - &(async->cmd.convert_arg), - async->cmd. - flags & TRIG_ROUND_MASK); - if (das800_set_frequency(dev) < 0) { - comedi_error(dev, "Error setting up counters"); - return -1; - } - break; - case TRIG_EXT: - break; - default: - break; + das800_set_frequency(dev); } spin_lock_irqsave(&dev->spinlock, irq_flags); - outb(CONV_CONTROL, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be conversion control register */ - outb(conv_bits, dev->iobase + DAS800_CONV_CONTROL); + das800_ind_write(dev, conv_bits, CONV_CONTROL); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - async->events = 0; - enable_das800(dev); + + das800_enable(dev); return 0; } -static int das800_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static unsigned int das800_ai_get_sample(struct comedi_device *dev) +{ + unsigned int lsb = inb(dev->iobase + DAS800_LSB); + unsigned int msb = inb(dev->iobase + DAS800_MSB); + + return (msb << 8) | lsb; +} + +static irqreturn_t das800_interrupt(int irq, void *d) { - int i, n; - int chan; - int range; - int lsb, msb; - int timeout = 1000; + struct comedi_device *dev = d; + struct das800_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async; + struct comedi_cmd *cmd; unsigned long irq_flags; + unsigned int status; + unsigned int val; + bool fifo_empty; + bool fifo_overflow; + int i; - disable_das800(dev); /* disable hardware conversions (enables software conversions) */ + status = inb(dev->iobase + DAS800_STATUS); + if (!(status & IRQ)) + return IRQ_NONE; + if (!dev->attached) + return IRQ_HANDLED; - /* set multiplexer */ - chan = CR_CHAN(insn->chanspec); + async = s->async; + cmd = &async->cmd; spin_lock_irqsave(&dev->spinlock, irq_flags); - outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ - outb(chan | devpriv->do_bits, dev->iobase + DAS800_CONTROL1); + status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN; + /* + * Don't release spinlock yet since we want to make sure + * no one else disables hardware conversions. + */ + + /* if hardware conversions are not enabled, then quit */ + if (status == 0) { + spin_unlock_irqrestore(&dev->spinlock, irq_flags); + return IRQ_HANDLED; + } + + for (i = 0; i < DAS802_16_HALF_FIFO_SZ; i++) { + val = das800_ai_get_sample(dev); + if (s->maxdata == 0x0fff) { + fifo_empty = !!(val & FIFO_EMPTY); + fifo_overflow = !!(val & FIFO_OVF); + } else { + /* cio-das802/16 has no fifo empty status bit */ + fifo_empty = false; + fifo_overflow = !!(inb(dev->iobase + DAS800_GAIN) & + CIO_FFOV); + } + if (fifo_empty || fifo_overflow) + break; + + if (s->maxdata == 0x0fff) + val >>= 4; /* 12-bit sample */ + + /* if there are more data points to collect */ + if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) { + /* write data point to buffer */ + cfc_write_to_buffer(s, val & s->maxdata); + devpriv->count--; + } + } + async->events |= COMEDI_CB_BLOCK; + + if (fifo_overflow) { + spin_unlock_irqrestore(&dev->spinlock, irq_flags); + async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + cfc_handle_events(dev, s); + return IRQ_HANDLED; + } + + if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) { + /* Re-enable card's interrupt. + * We already have spinlock, so indirect addressing is safe */ + das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, + CONTROL1); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); + } else { + /* otherwise, stop taking data */ + spin_unlock_irqrestore(&dev->spinlock, irq_flags); + das800_disable(dev); + async->events |= COMEDI_CB_EOA; + } + cfc_handle_events(dev, s); + return IRQ_HANDLED; +} + +static int das800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DAS800_STATUS); + if ((status & BUSY) == 0) + return 0; + return -EBUSY; +} + +static int das800_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct das800_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned long irq_flags; + unsigned int val; + int ret; + int i; + + das800_disable(dev); + + /* set multiplexer */ + spin_lock_irqsave(&dev->spinlock, irq_flags); + das800_ind_write(dev, chan | devpriv->do_bits, CONTROL1); spin_unlock_irqrestore(&dev->spinlock, irq_flags); /* set gain / range */ - range = CR_RANGE(insn->chanspec); - if (thisboard->resolution == 12 && range) + if (s->maxdata == 0x0fff && range) range += 0x7; range &= 0xf; outb(range, dev->iobase + DAS800_GAIN); udelay(5); - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { /* trigger conversion */ outb_p(0, dev->iobase + DAS800_MSB); - for (i = 0; i < timeout; i++) { - if (!(inb(dev->iobase + DAS800_STATUS) & BUSY)) - break; - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } - lsb = inb(dev->iobase + DAS800_LSB); - msb = inb(dev->iobase + DAS800_MSB); - if (thisboard->resolution == 12) { - data[n] = (lsb >> 4) & 0xff; - data[n] |= (msb << 4); - } else { - data[n] = (msb << 8) | lsb; - } + ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0); + if (ret) + return ret; + + val = das800_ai_get_sample(dev); + if (s->maxdata == 0x0fff) + val >>= 4; /* 12-bit sample */ + data[i] = val & s->maxdata; } - return n; + return insn->n; } -static int das800_di_rbits(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int das800_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int bits; + data[1] = (inb(dev->iobase + DAS800_STATUS) >> 4) & 0x7; - bits = inb(dev->iobase + DAS800_STATUS) >> 4; - bits &= 0x7; - data[1] = bits; - data[0] = 0; - - return 2; + return insn->n; } -static int das800_do_wbits(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int das800_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int wbits; + struct das800_private *devpriv = dev->private; unsigned long irq_flags; - /* only set bits that have been masked */ - data[0] &= 0xf; - wbits = devpriv->do_bits >> 4; - wbits &= ~data[0]; - wbits |= data[0] & data[1]; - devpriv->do_bits = wbits << 4; + if (comedi_dio_update_state(s, data)) { + devpriv->do_bits = s->state << 4; + + spin_lock_irqsave(&dev->spinlock, irq_flags); + das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, + CONTROL1); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); + } + + data[1] = s->state; + + return insn->n; +} + +static int das800_probe(struct comedi_device *dev) +{ + const struct das800_board *thisboard = comedi_board(dev); + int board = thisboard ? thisboard - das800_boards : -EINVAL; + int id_bits; + unsigned long irq_flags; spin_lock_irqsave(&dev->spinlock, irq_flags); - outb(CONTROL1, dev->iobase + DAS800_GAIN); /* select dev->iobase + 2 to be control register 1 */ - outb(devpriv->do_bits | CONTROL1_INTE, dev->iobase + DAS800_CONTROL1); + id_bits = das800_ind_read(dev, ID) & 0x3; spin_unlock_irqrestore(&dev->spinlock, irq_flags); - data[1] = wbits; - - return 2; + switch (id_bits) { + case 0x0: + if (board == BOARD_DAS800 || board == BOARD_CIODAS800) + break; + dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n"); + board = BOARD_DAS800; + break; + case 0x2: + if (board == BOARD_DAS801 || board == BOARD_CIODAS801) + break; + dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n"); + board = BOARD_DAS801; + break; + case 0x3: + if (board == BOARD_DAS802 || board == BOARD_CIODAS802 || + board == BOARD_CIODAS80216) + break; + dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n"); + board = BOARD_DAS802; + break; + default: + dev_dbg(dev->class_dev, "Board model: 0x%x (unknown)\n", + id_bits); + board = -EINVAL; + break; + } + return board; } -/* loads counters with divisor1, divisor2 from private structure */ -static int das800_set_frequency(struct comedi_device *dev) +static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int err = 0; + const struct das800_board *thisboard; + struct das800_private *devpriv; + struct comedi_subdevice *s; + unsigned int irq = it->options[1]; + unsigned long irq_flags; + int board; + int ret; - if (i8254_load(dev->iobase + DAS800_8254, 0, 1, devpriv->divisor1, 2)) - err++; - if (i8254_load(dev->iobase + DAS800_8254, 0, 2, devpriv->divisor2, 2)) - err++; - if (err) - return -1; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], DAS800_SIZE); + if (ret) + return ret; + + board = das800_probe(dev); + if (board < 0) { + dev_dbg(dev->class_dev, "unable to determine board type\n"); + return -ENODEV; + } + dev->board_ptr = das800_boards + board; + thisboard = comedi_board(dev); + dev->board_name = thisboard->name; + + if (irq > 1 && irq <= 7) { + ret = request_irq(irq, das800_interrupt, 0, dev->board_name, + dev); + if (ret == 0) + dev->irq = irq; + } + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8; + s->maxdata = (1 << thisboard->resolution) - 1; + s->range_table = thisboard->ai_range; + s->insn_read = das800_ai_insn_read; + if (dev->irq) { + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 8; + s->do_cmdtest = das800_ai_do_cmdtest; + s->do_cmd = das800_ai_do_cmd; + s->cancel = das800_cancel; + } + + /* Digital Input subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 3; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das800_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = das800_do_insn_bits; + + das800_disable(dev); + + /* initialize digital out channels */ + spin_lock_irqsave(&dev->spinlock, irq_flags); + das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1); + spin_unlock_irqrestore(&dev->spinlock, irq_flags); return 0; -} +}; + +static struct comedi_driver driver_das800 = { + .driver_name = "das800", + .module = THIS_MODULE, + .attach = das800_attach, + .detach = comedi_legacy_detach, + .num_names = ARRAY_SIZE(das800_boards), + .board_name = &das800_boards[0].name, + .offset = sizeof(struct das800_board), +}; +module_comedi_driver(driver_das800); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 2b4e6e6eb82..ad7a5d53b97 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dmm32at @@ -37,9 +32,12 @@ Configuration Options: comedi_config /dev/comedi0 dmm32at baseaddr,irq */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> + +#include "comedi_fc.h" /* Board register addresses */ @@ -78,9 +76,6 @@ Configuration Options: #define DMM32AT_DIOC 0x0e #define DMM32AT_DIOCONF 0x0f -#define dmm_inb(cdev, reg) inb((cdev->iobase)+reg) -#define dmm_outb(cdev, reg, valu) outb(valu, (cdev->iobase)+reg) - /* Board register values. */ /* DMM32AT_DACSTAT 0x04 */ @@ -129,13 +124,12 @@ Configuration Options: /* board AI ranges in comedi structure */ static const struct comedi_lrange dmm32at_airanges = { - 4, - { - UNI_RANGE(10), - UNI_RANGE(5), - BIP_RANGE(10), - BIP_RANGE(5), - } + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + BIP_RANGE(10), + BIP_RANGE(5) + } }; /* register values for above ranges */ @@ -150,54 +144,14 @@ static const unsigned char dmm32at_rangebits[] = { * board. The application should only use the range set by the jumper */ static const struct comedi_lrange dmm32at_aoranges = { - 4, - { - UNI_RANGE(10), - UNI_RANGE(5), - BIP_RANGE(10), - BIP_RANGE(5), - } -}; - -/* - * 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. - */ -struct dmm32at_board { - const char *name; - int ai_chans; - int ai_bits; - const struct comedi_lrange *ai_ranges; - int ao_chans; - int ao_bits; - const struct comedi_lrange *ao_ranges; - int have_dio; - int dio_chans; -}; -static const struct dmm32at_board dmm32at_boards[] = { - { - .name = "dmm32at", - .ai_chans = 32, - .ai_bits = 16, - .ai_ranges = &dmm32at_airanges, - .ao_chans = 4, - .ao_bits = 12, - .ao_ranges = &dmm32at_aoranges, - .have_dio = 1, - .dio_chans = 24, - }, + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + BIP_RANGE(10), + BIP_RANGE(5) + } }; -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct dmm32at_board *)dev->board_ptr) - -/* 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 dmm32at_private { int data; @@ -210,326 +164,63 @@ struct dmm32at_private { }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct dmm32at_private *)dev->private) - -/* - * 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 int dmm32at_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dmm32at_detach(struct comedi_device *dev); -static struct comedi_driver driver_dmm32at = { - .driver_name = "dmm32at", - .module = THIS_MODULE, - .attach = dmm32at_attach, - .detach = dmm32at_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 dmm32at_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 = &dmm32at_boards[0].name, - .offset = sizeof(struct dmm32at_board), - .num_names = ARRAY_SIZE(dmm32at_boards), -}; - -/* prototypes for driver functions below */ -static int dmm32at_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dmm32at_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dmm32at_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dmm32at_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dmm32at_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int dmm32at_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int dmm32at_ai_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int dmm32at_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static int dmm32at_ns_to_timer(unsigned int *ns, int round); -static irqreturn_t dmm32at_isr(int irq, void *d); -void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int dmm32at_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int dmm32at_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int ret; - struct comedi_subdevice *s; - unsigned char aihi, ailo, fifostat, aistat, intstat, airback; - unsigned long iobase; - unsigned int irq; - - iobase = it->options[0]; - irq = it->options[1]; - - printk(KERN_INFO "comedi%d: dmm32at: attaching\n", dev->minor); - printk(KERN_DEBUG "dmm32at: probing at address 0x%04lx, irq %u\n", - iobase, irq); - - /* register address space */ - if (!request_region(iobase, DMM32AT_MEMSIZE, thisboard->name)) { - printk(KERN_ERR "comedi%d: dmm32at: I/O port conflict\n", - dev->minor); - return -EIO; - } - dev->iobase = iobase; - - /* the following just makes sure the board is there and gets - it to a known state */ - - /* reset the board */ - dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_RESET); - - /* allow a millisecond to reset */ - udelay(1000); - - /* zero scan and fifo control */ - dmm_outb(dev, DMM32AT_FIFOCNTRL, 0x0); - - /* zero interrupt and clock control */ - dmm_outb(dev, DMM32AT_INTCLOCK, 0x0); - - /* write a test channel range, the high 3 bits should drop */ - dmm_outb(dev, DMM32AT_AILOW, 0x80); - dmm_outb(dev, DMM32AT_AIHIGH, 0xff); - - /* set the range at 10v unipolar */ - dmm_outb(dev, DMM32AT_AICONF, DMM32AT_RANGE_U10); - - /* should take 10 us to settle, here's a hundred */ - udelay(100); - - /* read back the values */ - ailo = dmm_inb(dev, DMM32AT_AILOW); - aihi = dmm_inb(dev, DMM32AT_AIHIGH); - fifostat = dmm_inb(dev, DMM32AT_FIFOSTAT); - aistat = dmm_inb(dev, DMM32AT_AISTAT); - intstat = dmm_inb(dev, DMM32AT_INTCLOCK); - airback = dmm_inb(dev, DMM32AT_AIRBACK); - - printk(KERN_DEBUG "dmm32at: lo=0x%02x hi=0x%02x fifostat=0x%02x\n", - ailo, aihi, fifostat); - printk(KERN_DEBUG - "dmm32at: aistat=0x%02x intstat=0x%02x airback=0x%02x\n", - aistat, intstat, airback); - - if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) || - (aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) { - printk(KERN_ERR "dmmat32: board detection failed\n"); - return -EIO; - } - - /* board is there, register interrupt */ - if (irq) { - ret = request_irq(irq, dmm32at_isr, 0, thisboard->name, dev); - if (ret < 0) { - printk(KERN_ERR "dmm32at: irq conflict\n"); - return ret; - } - dev->irq = irq; - } - -/* - * 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 = dmm32at_probe(dev); */ - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct dmm32at_private)) < 0) - return -ENOMEM; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - dev->read_subdev = s; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - /* we support single-ended (ground) and differential */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; - s->n_chan = thisboard->ai_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = thisboard->ai_ranges; - s->len_chanlist = 32; /* This is the maximum chanlist length that - the board can handle */ - s->insn_read = dmm32at_ai_rinsn; - s->do_cmd = dmm32at_ai_cmd; - s->do_cmdtest = dmm32at_ai_cmdtest; - s->cancel = dmm32at_ai_cancel; - - s = dev->subdevices + 1; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->ao_chans; - s->maxdata = (1 << thisboard->ao_bits) - 1; - s->range_table = thisboard->ao_ranges; - s->insn_write = dmm32at_ao_winsn; - s->insn_read = dmm32at_ao_rinsn; - - s = dev->subdevices + 2; - /* digital i/o subdevice */ - if (thisboard->have_dio) { - - /* get access to the DIO regs */ - dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC); - /* set the DIO's to the defualt input setting */ - devpriv->dio_config = DMM32AT_DIRA | DMM32AT_DIRB | - DMM32AT_DIRCL | DMM32AT_DIRCH | DMM32AT_DIENABLE; - dmm_outb(dev, DMM32AT_DIOCONF, devpriv->dio_config); - - /* set up the subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->dio_chans; - s->maxdata = 1; - s->state = 0; - s->range_table = &range_digital; - s->insn_bits = dmm32at_dio_insn_bits; - s->insn_config = dmm32at_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /* success */ - printk(KERN_INFO "comedi%d: dmm32at: attached\n", dev->minor); - - return 1; - -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int dmm32at_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: dmm32at: remove\n", dev->minor); - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, DMM32AT_MEMSIZE); + unsigned char status; - return 0; + status = inb(dev->iobase + context); + if ((status & DMM32AT_STATUS) == 0) + return 0; + return -EBUSY; } -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ - static int dmm32at_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + int n; unsigned int d; - unsigned char status; unsigned short msb, lsb; unsigned char chan; int range; + int ret; /* get the channel and range number */ chan = CR_CHAN(insn->chanspec) & (s->n_chan - 1); range = CR_RANGE(insn->chanspec); - /* printk("channel=0x%02x, range=%d\n",chan,range); */ - /* zero scan and fifo control and reset fifo */ - dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET); + outb(DMM32AT_FIFORESET, dev->iobase + DMM32AT_FIFOCNTRL); /* write the ai channel range regs */ - dmm_outb(dev, DMM32AT_AILOW, chan); - dmm_outb(dev, DMM32AT_AIHIGH, chan); + outb(chan, dev->iobase + DMM32AT_AILOW); + outb(chan, dev->iobase + DMM32AT_AIHIGH); /* set the range bits */ - dmm_outb(dev, DMM32AT_AICONF, dmm32at_rangebits[range]); + outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = dmm_inb(dev, DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) { - printk(KERN_WARNING "dmm32at: timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ - dmm_outb(dev, DMM32AT_CONV, 0xff); + outb(0xff, dev->iobase + DMM32AT_CONV); + /* wait for conversion to end */ - for (i = 0; i < 40000; i++) { - status = dmm_inb(dev, DMM32AT_AISTAT); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) { - printk(KERN_WARNING "dmm32at: timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, dmm32at_ai_status, + DMM32AT_AISTAT); + if (ret) + return ret; /* read data */ - lsb = dmm_inb(dev, DMM32AT_AILSB); - msb = dmm_inb(dev, DMM32AT_AIMSB); + lsb = inb(dev->iobase + DMM32AT_AILSB); + msb = inb(dev->iobase + DMM32AT_AIMSB); /* invert sign bit to make range unsigned, this is an idiosyncrasy of the diamond board, it return @@ -546,95 +237,89 @@ static int dmm32at_ai_rinsn(struct comedi_device *dev, return n; } -static int dmm32at_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int dmm32at_ns_to_timer(unsigned int *ns, int round) { - int err = 0; - int tmp; - int start_chan, gain, i; - - /* printk("dmmat32 in command test\n"); */ + /* trivial timer */ + return *ns; +} - /* 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 dmm32at_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int range0 = CR_RANGE(cmd->chanlist[0]); + int i; - /* step 1: make sure trigger sources are trivially valid */ + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + if (chan != (chan0 + i) % s->n_chan) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); + return -EINVAL; + } + if (range != range0) { + dev_dbg(dev->class_dev, + "entries in chanlist must all have the same gain\n"); + return -EINVAL; + } + } - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER /*| TRIG_EXT */ ; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + return 0; +} - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER /*| TRIG_EXT */ ; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; +static int dmm32at_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + int err = 0; + unsigned int arg; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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 2: make sure trigger sources are unique and mutually - * compatible */ + /* 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); - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } #define MAX_SCAN_SPEED 1000000 /* in nanoseconds */ #define MIN_SCAN_SPEED 1000000000 /* in nanoseconds */ if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < MAX_SCAN_SPEED) { - cmd->scan_begin_arg = MAX_SCAN_SPEED; - err++; - } - if (cmd->scan_begin_arg > MIN_SCAN_SPEED) { - cmd->scan_begin_arg = MIN_SCAN_SPEED; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + MAX_SCAN_SPEED); + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, + MIN_SCAN_SPEED); } else { /* external trigger */ /* should be level/edge, hi/lo specification here */ /* should specify multiple external triggers */ - if (cmd->scan_begin_arg > 9) { - cmd->scan_begin_arg = 9; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); } + if (cmd->convert_src == TRIG_TIMER) { if (cmd->convert_arg >= 17500) cmd->convert_arg = 20000; @@ -644,35 +329,20 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, cmd->convert_arg = 10000; else cmd->convert_arg = 5000; - } else { /* external trigger */ /* see above */ - if (cmd->convert_arg > 9) { - cmd->convert_arg = 9; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg > 0xfffffff0) { - cmd->stop_arg = 0xfffffff0; - err++; - } - if (cmd->stop_arg == 0) { - cmd->stop_arg = 1; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->stop_arg, 0xfffffff0); + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -681,50 +351,28 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - dmm32at_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + dmm32at_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - dmm32at_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + dmm32at_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } if (err) return 4; - /* step 5 check the channel list, the channel list for this - board must be consecutive and gains must be the same */ - - if (cmd->chanlist) { - gain = CR_RANGE(cmd->chanlist[0]); - start_chan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != - (start_chan + i) % s->n_chan) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - if (CR_RANGE(cmd->chanlist[i]) != gain) { - comedi_error(dev, - "entries in chanlist must all have the same gain\n"); - err++; - } - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= dmm32at_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -732,11 +380,43 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, return 0; } +static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec) +{ + unsigned char lo1, lo2, hi2; + unsigned short both2; + + /* based on 10mhz clock */ + lo1 = 200; + both2 = nansec / 20000; + hi2 = (both2 & 0xff00) >> 8; + lo2 = both2 & 0x00ff; + + /* set the counter frequency to 10mhz */ + outb(0, dev->iobase + DMM32AT_CNTRDIO); + + /* get access to the clock regs */ + outb(DMM32AT_CLKACC, dev->iobase + DMM32AT_CNTRL); + + /* write the counter 1 control word and low byte to counter */ + outb(DMM32AT_CLKCT1, dev->iobase + DMM32AT_CLKCT); + outb(lo1, dev->iobase + DMM32AT_CLK1); + + /* write the counter 2 control word and low byte then to counter */ + outb(DMM32AT_CLKCT2, dev->iobase + DMM32AT_CLKCT); + outb(lo2, dev->iobase + DMM32AT_CLK2); + outb(hi2, dev->iobase + DMM32AT_CLK2); + + /* enable the ai conversion interrupt and the clock to start scans */ + outb(DMM32AT_ADINT | DMM32AT_CLKSEL, dev->iobase + DMM32AT_INTCLOCK); +} + static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct dmm32at_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int i, range; - unsigned char chanlo, chanhi, status; + int range; + unsigned char chanlo, chanhi; + int ret; if (!cmd->chanlist) return -EINVAL; @@ -749,20 +429,20 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) range = CR_RANGE(cmd->chanlist[0]); /* reset fifo */ - dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_FIFORESET); + outb(DMM32AT_FIFORESET, dev->iobase + DMM32AT_FIFOCNTRL); /* set scan enable */ - dmm_outb(dev, DMM32AT_FIFOCNTRL, DMM32AT_SCANENABLE); + outb(DMM32AT_SCANENABLE, dev->iobase + DMM32AT_FIFOCNTRL); /* write the ai channel range regs */ - dmm_outb(dev, DMM32AT_AILOW, chanlo); - dmm_outb(dev, DMM32AT_AIHIGH, chanhi); + outb(chanlo, dev->iobase + DMM32AT_AILOW); + outb(chanhi, dev->iobase + DMM32AT_AIHIGH); /* set the range bits */ - dmm_outb(dev, DMM32AT_AICONF, dmm32at_rangebits[range]); + outb(dmm32at_rangebits[range], dev->iobase + DMM32AT_AICONF); /* reset the interrupt just in case */ - dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_INTRESET); + outb(DMM32AT_INTRESET, dev->iobase + DMM32AT_CNTRL); if (cmd->stop_src == TRIG_COUNT) devpriv->ai_scans_left = cmd->stop_arg; @@ -771,34 +451,23 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * isr */ } - /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = dmm_inb(dev, DMM32AT_AIRBACK); - if ((status & DMM32AT_STATUS) == 0) - break; - } - if (i == 40000) { - printk(KERN_WARNING "dmm32at: timeout\n"); - return -ETIMEDOUT; - } + /* + * wait for circuit to settle + * we don't have the 'insn' here but it's not needed + */ + ret = comedi_timeout(dev, s, NULL, dmm32at_ai_status, DMM32AT_AIRBACK); + if (ret) + return ret; if (devpriv->ai_scans_left > 1) { /* start the clock and enable the interrupts */ dmm32at_setaitimer(dev, cmd->scan_begin_arg); } else { /* start the interrups and initiate a single scan */ - dmm_outb(dev, DMM32AT_INTCLOCK, DMM32AT_ADINT); - dmm_outb(dev, DMM32AT_CONV, 0xff); + outb(DMM32AT_ADINT, dev->iobase + DMM32AT_INTCLOCK); + outb(0xff, dev->iobase + DMM32AT_CONV); } -/* printk("dmmat32 in command\n"); */ - -/* for(i=0;i<cmd->chanlist_len;i++) */ -/* comedi_buf_put(s->async,i*100); */ - -/* s->async->events |= COMEDI_CB_EOA; */ -/* comedi_event(dev, s); */ - return 0; } @@ -806,24 +475,27 @@ static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int dmm32at_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct dmm32at_private *devpriv = dev->private; + devpriv->ai_scans_left = 1; return 0; } static irqreturn_t dmm32at_isr(int irq, void *d) { + struct comedi_device *dev = d; + struct dmm32at_private *devpriv = dev->private; unsigned char intstat; unsigned int samp; unsigned short msb, lsb; int i; - struct comedi_device *dev = d; if (!dev->attached) { comedi_error(dev, "spurious interrupt"); return IRQ_HANDLED; } - intstat = dmm_inb(dev, DMM32AT_INTCLOCK); + intstat = inb(dev->iobase + DMM32AT_INTCLOCK); if (intstat & DMM32AT_ADINT) { struct comedi_subdevice *s = dev->read_subdev; @@ -831,19 +503,19 @@ static irqreturn_t dmm32at_isr(int irq, void *d) for (i = 0; i < cmd->chanlist_len; i++) { /* read data */ - lsb = dmm_inb(dev, DMM32AT_AILSB); - msb = dmm_inb(dev, DMM32AT_AIMSB); + lsb = inb(dev->iobase + DMM32AT_AILSB); + msb = inb(dev->iobase + DMM32AT_AIMSB); /* invert sign bit to make range unsigned */ samp = ((msb ^ 0x0080) << 8) + lsb; - comedi_buf_put(s->async, samp); + comedi_buf_put(s, samp); } if (devpriv->ai_scans_left != 0xffffffff) { /* TRIG_COUNT */ devpriv->ai_scans_left--; if (devpriv->ai_scans_left == 0) { /* disable further interrupts and clocks */ - dmm_outb(dev, DMM32AT_INTCLOCK, 0x0); + outb(0x0, dev->iobase + DMM32AT_INTCLOCK); /* set the buffer to be flushed with an EOF */ s->async->events |= COMEDI_CB_EOA; } @@ -854,34 +526,32 @@ static irqreturn_t dmm32at_isr(int irq, void *d) } /* reset the interrupt */ - dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_INTRESET); + outb(DMM32AT_INTRESET, dev->iobase + DMM32AT_CNTRL); return IRQ_HANDLED; } -/* 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 dmm32at_ns_to_timer(unsigned int *ns, int round) +static int dmm32at_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - /* 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 - */ + unsigned char status; - return *ns; + status = inb(dev->iobase + DMM32AT_DACSTAT); + if ((status & DMM32AT_DACBUSY) == 0) + return 0; + return -EBUSY; } static int dmm32at_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct dmm32at_private *devpriv = dev->private; 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. */ @@ -893,23 +563,17 @@ static int dmm32at_ao_winsn(struct comedi_device *dev, lo = data[i] & 0x00ff; /* high byte also contains channel number */ hi = (data[i] >> 8) + chan * (1 << 6); - /* printk("writing 0x%02x 0x%02x\n",hi,lo); */ /* write the low and high values to the board */ - dmm_outb(dev, DMM32AT_DACLSB, lo); - dmm_outb(dev, DMM32AT_DACMSB, hi); + outb(lo, dev->iobase + DMM32AT_DACLSB); + outb(hi, dev->iobase + DMM32AT_DACMSB); /* wait for circuit to settle */ - for (i = 0; i < 40000; i++) { - status = dmm_inb(dev, DMM32AT_DACSTAT); - if ((status & DMM32AT_DACBUSY) == 0) - break; - } - if (i == 40000) { - printk(KERN_WARNING "dmm32at: timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, dmm32at_ao_eoc, 0); + if (ret) + return ret; + /* dummy read to update trigger the output */ - status = dmm_inb(dev, DMM32AT_DACMSB); + status = inb(dev->iobase + DMM32AT_DACMSB); } @@ -917,12 +581,11 @@ static int dmm32at_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 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); @@ -932,149 +595,211 @@ static int dmm32at_ao_rinsn(struct comedi_device *dev, 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 dmm32at_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned char diobits; + struct dmm32at_private *devpriv = dev->private; + unsigned int mask; + unsigned int val; - if (insn->n != 2) - return -EINVAL; + mask = comedi_dio_update_state(s, data); + if (mask) { + /* get access to the DIO regs */ + outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - /* outw(s->state,dev->iobase + DMM32AT_DIO); */ + /* if either part of dio is set for output */ + if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) || + ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) { + val = (s->state & 0x00ff0000) >> 16; + outb(val, dev->iobase + DMM32AT_DIOC); + } + if ((devpriv->dio_config & DMM32AT_DIRB) == 0) { + val = (s->state & 0x0000ff00) >> 8; + outb(val, dev->iobase + DMM32AT_DIOB); + } + if ((devpriv->dio_config & DMM32AT_DIRA) == 0) { + val = (s->state & 0x000000ff); + outb(val, dev->iobase + DMM32AT_DIOA); + } } - /* get access to the DIO regs */ - dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC); + val = inb(dev->iobase + DMM32AT_DIOA); + val |= inb(dev->iobase + DMM32AT_DIOB) << 8; + val |= inb(dev->iobase + DMM32AT_DIOC) << 16; + s->state = val; - /* if either part of dio is set for output */ - if (((devpriv->dio_config & DMM32AT_DIRCL) == 0) || - ((devpriv->dio_config & DMM32AT_DIRCH) == 0)) { - diobits = (s->state & 0x00ff0000) >> 16; - dmm_outb(dev, DMM32AT_DIOC, diobits); - } - if ((devpriv->dio_config & DMM32AT_DIRB) == 0) { - diobits = (s->state & 0x0000ff00) >> 8; - dmm_outb(dev, DMM32AT_DIOB, diobits); - } - if ((devpriv->dio_config & DMM32AT_DIRA) == 0) { - diobits = (s->state & 0x000000ff); - dmm_outb(dev, DMM32AT_DIOA, diobits); - } + data[1] = val; - /* now read the state back in */ - s->state = dmm_inb(dev, DMM32AT_DIOC); - s->state <<= 8; - s->state |= dmm_inb(dev, DMM32AT_DIOB); - s->state <<= 8; - s->state |= dmm_inb(dev, DMM32AT_DIOA); - data[1] = s->state; - - /* on return, data[1] contains the value of the digital - * input and output lines. */ - /* data[1]=inw(dev->iobase + DMM32AT_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 2; + return insn->n; } static int dmm32at_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct dmm32at_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; unsigned char chanbit; - int chan = CR_CHAN(insn->chanspec); - - if (insn->n != 1) - return -EINVAL; + int ret; - if (chan < 8) + if (chan < 8) { + mask = 0x0000ff; chanbit = DMM32AT_DIRA; - else if (chan < 16) + } else if (chan < 16) { + mask = 0x00ff00; chanbit = DMM32AT_DIRB; - else if (chan < 20) + } else if (chan < 20) { + mask = 0x0f0000; chanbit = DMM32AT_DIRCL; - else + } else { + mask = 0xf00000; chanbit = DMM32AT_DIRCH; + } - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; - /* if output clear the bit, otherwise set it */ - if (data[0] == COMEDI_OUTPUT) + if (data[0] == INSN_CONFIG_DIO_OUTPUT) devpriv->dio_config &= ~chanbit; else devpriv->dio_config |= chanbit; /* get access to the DIO regs */ - dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_DIOACC); + outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); /* set the DIO's to the new configuration setting */ - dmm_outb(dev, DMM32AT_DIOCONF, devpriv->dio_config); + outb(devpriv->dio_config, dev->iobase + DMM32AT_DIOCONF); - return 1; + return insn->n; } -void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec) +static int dmm32at_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { - unsigned char lo1, lo2, hi2; - unsigned short both2; + struct dmm32at_private *devpriv; + int ret; + struct comedi_subdevice *s; + unsigned char aihi, ailo, fifostat, aistat, intstat, airback; - /* based on 10mhz clock */ - lo1 = 200; - both2 = nansec / 20000; - hi2 = (both2 & 0xff00) >> 8; - lo2 = both2 & 0x00ff; + ret = comedi_request_region(dev, it->options[0], DMM32AT_MEMSIZE); + if (ret) + return ret; - /* set the counter frequency to 10mhz */ - dmm_outb(dev, DMM32AT_CNTRDIO, 0); + /* the following just makes sure the board is there and gets + it to a known state */ - /* get access to the clock regs */ - dmm_outb(dev, DMM32AT_CNTRL, DMM32AT_CLKACC); + /* reset the board */ + outb(DMM32AT_RESET, dev->iobase + DMM32AT_CNTRL); - /* write the counter 1 control word and low byte to counter */ - dmm_outb(dev, DMM32AT_CLKCT, DMM32AT_CLKCT1); - dmm_outb(dev, DMM32AT_CLK1, lo1); + /* allow a millisecond to reset */ + udelay(1000); - /* write the counter 2 control word and low byte then to counter */ - dmm_outb(dev, DMM32AT_CLKCT, DMM32AT_CLKCT2); - dmm_outb(dev, DMM32AT_CLK2, lo2); - dmm_outb(dev, DMM32AT_CLK2, hi2); + /* zero scan and fifo control */ + outb(0x0, dev->iobase + DMM32AT_FIFOCNTRL); - /* enable the ai conversion interrupt and the clock to start scans */ - dmm_outb(dev, DMM32AT_INTCLOCK, DMM32AT_ADINT | DMM32AT_CLKSEL); + /* zero interrupt and clock control */ + outb(0x0, dev->iobase + DMM32AT_INTCLOCK); -} + /* write a test channel range, the high 3 bits should drop */ + outb(0x80, dev->iobase + DMM32AT_AILOW); + outb(0xff, dev->iobase + DMM32AT_AIHIGH); -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_dmm32at_init_module(void) -{ - return comedi_driver_register(&driver_dmm32at); -} + /* set the range at 10v unipolar */ + outb(DMM32AT_RANGE_U10, dev->iobase + DMM32AT_AICONF); -static void __exit driver_dmm32at_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dmm32at); + /* should take 10 us to settle, here's a hundred */ + udelay(100); + + /* read back the values */ + ailo = inb(dev->iobase + DMM32AT_AILOW); + aihi = inb(dev->iobase + DMM32AT_AIHIGH); + fifostat = inb(dev->iobase + DMM32AT_FIFOSTAT); + aistat = inb(dev->iobase + DMM32AT_AISTAT); + intstat = inb(dev->iobase + DMM32AT_INTCLOCK); + airback = inb(dev->iobase + DMM32AT_AIRBACK); + + if ((ailo != 0x00) || (aihi != 0x1f) || (fifostat != 0x80) || + (aistat != 0x60 || (intstat != 0x00) || airback != 0x0c)) { + dev_err(dev->class_dev, "board detection failed\n"); + return -EIO; + } + + if (it->options[1]) { + ret = request_irq(it->options[1], dmm32at_isr, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; + } + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + s = &dev->subdevices[0]; + /* 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 = 32; + s->maxdata = 0xffff; + s->range_table = &dmm32at_airanges; + s->insn_read = dmm32at_ai_rinsn; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 32; + s->do_cmd = dmm32at_ai_cmd; + s->do_cmdtest = dmm32at_ai_cmdtest; + s->cancel = dmm32at_ai_cancel; + } + + s = &dev->subdevices[1]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + 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 = &dev->subdevices[2]; + /* digital i/o subdevice */ + + /* get access to the DIO regs */ + outb(DMM32AT_DIOACC, dev->iobase + DMM32AT_CNTRL); + /* set the DIO's to the defualt input setting */ + devpriv->dio_config = DMM32AT_DIRA | DMM32AT_DIRB | + DMM32AT_DIRCL | DMM32AT_DIRCH | DMM32AT_DIENABLE; + outb(devpriv->dio_config, dev->iobase + DMM32AT_DIOCONF); + + /* set up the subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->state = 0; + s->range_table = &range_digital; + s->insn_bits = dmm32at_dio_insn_bits; + s->insn_config = dmm32at_dio_insn_config; + + return 0; } -module_init(driver_dmm32at_init_module); -module_exit(driver_dmm32at_cleanup_module); +static struct comedi_driver dmm32at_driver = { + .driver_name = "dmm32at", + .module = THIS_MODULE, + .attach = dmm32at_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(dmm32at_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index 5cce1b5f448..4263014426f 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -29,9 +29,9 @@ Configuration options: [5] - D/A 1 range (same choices) */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/ioport.h> #define DT2801_TIMEOUT 1000 @@ -88,83 +88,44 @@ Configuration options: #define DT2801_STATUS 1 #define DT2801_CMD 1 -static int dt2801_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2801_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2801 = { - .driver_name = "dt2801", - .module = THIS_MODULE, - .attach = dt2801_attach, - .detach = dt2801_detach, -}; - -static int __init driver_dt2801_init_module(void) -{ - return comedi_driver_register(&driver_dt2801); -} - -static void __exit driver_dt2801_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2801); -} - -module_init(driver_dt2801_init_module); -module_exit(driver_dt2801_cleanup_module); - #if 0 /* ignore 'defined but not used' warning */ -static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { 4, { - RANGE(-10, - 10), - RANGE(-5, - 5), - RANGE - (-2.5, - 2.5), - RANGE - (-1.25, - 1.25), - } +static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } }; #endif -static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { 4, { - RANGE(-10, - 10), - RANGE(-1, - 1), - RANGE - (-0.1, - 0.1), - RANGE - (-0.02, - 0.02), - } +static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { + 4, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02) + } }; #if 0 /* ignore 'defined but not used' warning */ -static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { 4, { - RANGE(0, - 10), - RANGE(0, - 5), - RANGE(0, - 2.5), - RANGE(0, - 1.25), - } +static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; #endif -static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { 4, { - RANGE(0, - 10), - RANGE(0, - 1), - RANGE(0, - 0.1), - RANGE(0, - 0.02), - } +static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { + 4, { + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) + } }; struct dt2801_board { @@ -248,32 +209,12 @@ static const struct dt2801_board boardtypes[] = { .dabits = 12}, }; -#define boardtype (*(const struct dt2801_board *)dev->board_ptr) - struct dt2801_private { const struct comedi_lrange *dac_range_types[2]; unsigned int ao_readback[2]; }; -#define devpriv ((struct dt2801_private *)dev->private) - -static int dt2801_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2801_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2801_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2801_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2801_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - /* These are the low-level routines: writecommand: write a command to the board writedata: write data byte @@ -303,7 +244,8 @@ static int dt2801_readdata(struct comedi_device *dev, int *data) static int dt2801_readdata2(struct comedi_device *dev, int *data) { - int lb, hb; + int lb = 0; + int hb = 0; int ret; ret = dt2801_readdata(dev, &lb); @@ -331,13 +273,6 @@ static int dt2801_writedata(struct comedi_device *dev, unsigned int data) outb_p(data & 0xff, dev->iobase + DT2801_DATA); return 0; } -#if 0 - if (stat & DT_S_READY) { - printk - ("dt2801: ready flag set (bad!) in dt2801_writedata()\n"); - return -EIO; - } -#endif } while (--timeout > 0); return -ETIME; @@ -385,11 +320,11 @@ static int dt2801_writecmd(struct comedi_device *dev, int command) stat = inb_p(dev->iobase + DT2801_STATUS); if (stat & DT_S_COMPOSITE_ERROR) { - printk - ("dt2801: composite-error in dt2801_writecmd(), ignoring\n"); + dev_dbg(dev->class_dev, + "composite-error in %s, ignoring\n", __func__); } if (!(stat & DT_S_READY)) - printk("dt2801: !ready in dt2801_writecmd(), ignoring\n"); + dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__); outb_p(command, dev->iobase + DT2801_CMD); return 0; @@ -401,17 +336,12 @@ static int dt2801_reset(struct comedi_device *dev) unsigned int stat; int timeout; - DPRINTK("dt2801: resetting board...\n"); - DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase), - inb_p(dev->iobase + 1)); - /* pull random data from data port */ inb_p(dev->iobase + DT2801_DATA); inb_p(dev->iobase + DT2801_DATA); inb_p(dev->iobase + DT2801_DATA); inb_p(dev->iobase + DT2801_DATA); - DPRINTK("dt2801: stop\n"); /* dt2801_writecmd(dev,DT_C_STOP); */ outb_p(DT_C_STOP, dev->iobase + DT2801_CMD); @@ -424,12 +354,10 @@ static int dt2801_reset(struct comedi_device *dev) break; } while (timeout--); if (!timeout) - printk("dt2801: timeout 1 status=0x%02x\n", stat); + dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat); - /* printk("dt2801: reading dummy\n"); */ /* dt2801_readdata(dev,&board_code); */ - DPRINTK("dt2801: reset\n"); outb_p(DT_C_RESET, dev->iobase + DT2801_CMD); /* dt2801_writecmd(dev,DT_C_RESET); */ @@ -441,13 +369,10 @@ static int dt2801_reset(struct comedi_device *dev) break; } while (timeout--); if (!timeout) - printk("dt2801: timeout 2 status=0x%02x\n", stat); + dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat); - DPRINTK("dt2801: reading code\n"); dt2801_readdata(dev, &board_code); - DPRINTK("dt2801: ok. code=0x%02x\n", board_code); - return board_code; } @@ -503,6 +428,112 @@ static const struct comedi_lrange *ai_range_lkup(int type, int opt) return &range_unknown; } +static int dt2801_error(struct comedi_device *dev, int stat) +{ + if (stat < 0) { + if (stat == -ETIME) + dev_dbg(dev->class_dev, "timeout\n"); + else + dev_dbg(dev->class_dev, "error %d\n", stat); + return stat; + } + dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat); + + dt2801_reset(dev); + dt2801_reset(dev); + + return -EIO; +} + +static int dt2801_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + int d; + int stat; + int i; + + for (i = 0; i < insn->n; i++) { + stat = 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); + + if (stat != 0) + return dt2801_error(dev, stat); + + data[i] = d; + } + + 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 dt2801_private *devpriv = dev->private; + + dt2801_writecmd(dev, DT_C_WRITE_DAIM); + dt2801_writedata(dev, CR_CHAN(insn->chanspec)); + dt2801_writedata2(dev, data[0]); + + devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; + + return 1; +} + +static int dt2801_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int which = (s == &dev->subdevices[3]) ? 1 : 0; + unsigned int val = 0; + + if (comedi_dio_update_state(s, data)) { + dt2801_writecmd(dev, DT_C_WRITE_DIG); + dt2801_writedata(dev, which); + dt2801_writedata(dev, s->state); + } + + dt2801_writecmd(dev, DT_C_READ_DIG); + dt2801_writedata(dev, which); + dt2801_readdata(dev, &val); + + data[1] = val; + + return insn->n; +} + +static int dt2801_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0xff); + if (ret) + return ret; + + dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN); + dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0); + + return insn->n; +} + /* options: [0] - i/o base @@ -514,18 +545,16 @@ static const struct comedi_lrange *ai_range_lkup(int type, int opt) */ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct dt2801_board *board; + struct dt2801_private *devpriv; struct comedi_subdevice *s; - unsigned long iobase; int board_code, type; int ret = 0; int n_ai_chans; - iobase = it->options[0]; - if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) { - comedi_error(dev, "I/O port conflict"); - return -EIO; - } - dev->iobase = iobase; + ret = comedi_request_region(dev, it->options[0], DT2801_IOSIZE); + if (ret) + return ret; /* do some checking */ @@ -539,28 +568,27 @@ static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (boardtypes[type].boardcode == board_code) goto havetype; } - printk("dt2801: unrecognized board code=0x%02x, contact author\n", - board_code); + dev_dbg(dev->class_dev, + "unrecognized board code=0x%02x, contact author\n", board_code); type = 0; havetype: dev->board_ptr = boardtypes + type; - printk("dt2801: %s at port 0x%lx", boardtype.name, iobase); + board = comedi_board(dev); n_ai_chans = probe_number_of_ai_chans(dev); - printk(" (ai channels = %d)", n_ai_chans); - ret = alloc_subdevices(dev, 4); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) goto out; - ret = alloc_private(dev, sizeof(struct dt2801_private)); - if (ret < 0) - goto out; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - dev->board_name = boardtype.name; + dev->board_name = board->name; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -568,27 +596,27 @@ havetype: s->n_chan = n_ai_chans; #else if (it->options[2]) - s->n_chan = boardtype.ad_chan; + s->n_chan = board->ad_chan; else - s->n_chan = boardtype.ad_chan / 2; + s->n_chan = board->ad_chan / 2; #endif - s->maxdata = (1 << boardtype.adbits) - 1; - s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]); + s->maxdata = (1 << board->adbits) - 1; + s->range_table = ai_range_lkup(board->adrangetype, it->options[3]); s->insn_read = dt2801_ai_insn_read; - s++; + s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; - s->maxdata = (1 << boardtype.dabits) - 1; + s->maxdata = (1 << board->dabits) - 1; 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++; + s = &dev->subdevices[2]; /* 1st digital subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -598,7 +626,7 @@ havetype: s->insn_bits = dt2801_dio_insn_bits; s->insn_config = dt2801_dio_insn_config; - s++; + s = &dev->subdevices[3]; /* 2nd digital subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -610,127 +638,16 @@ havetype: ret = 0; out: - printk("\n"); - return ret; } -static int dt2801_detach(struct comedi_device *dev) -{ - if (dev->iobase) - release_region(dev->iobase, DT2801_IOSIZE); - - return 0; -} - -static int dt2801_error(struct comedi_device *dev, int stat) -{ - if (stat < 0) { - if (stat == -ETIME) - printk("dt2801: timeout\n"); - else - printk("dt2801: error %d\n", stat); - return stat; - } - printk("dt2801: error status 0x%02x, resetting...\n", stat); - - dt2801_reset(dev); - dt2801_reset(dev); - - return -EIO; -} - -static int dt2801_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int d; - int stat; - int i; - - for (i = 0; i < insn->n; i++) { - stat = 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); - - if (stat != 0) - return dt2801_error(dev, stat); - - data[i] = d; - } - - return i; -} - -static int dt2801_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - 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) -{ - dt2801_writecmd(dev, DT_C_WRITE_DAIM); - dt2801_writedata(dev, CR_CHAN(insn->chanspec)); - dt2801_writedata2(dev, data[0]); - - devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0]; - - return 1; -} - -static int dt2801_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int which = 0; - - if (s == dev->subdevices + 4) - which = 1; - - if (insn->n != 2) - return -EINVAL; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - dt2801_writecmd(dev, DT_C_WRITE_DIG); - dt2801_writedata(dev, which); - dt2801_writedata(dev, s->state); - } - dt2801_writecmd(dev, DT_C_READ_DIG); - dt2801_writedata(dev, which); - dt2801_readdata(dev, data + 1); - - return 2; -} - -static int dt2801_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int which = 0; - - if (s == dev->subdevices + 4) - which = 1; - - /* configure */ - if (data[0]) { - s->io_bits = 0xff; - dt2801_writecmd(dev, DT_C_SET_DIGOUT); - } else { - s->io_bits = 0; - dt2801_writecmd(dev, DT_C_SET_DIGIN); - } - dt2801_writedata(dev, which); - - return 1; -} +static struct comedi_driver dt2801_driver = { + .driver_name = "dt2801", + .module = THIS_MODULE, + .attach = dt2801_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(dt2801_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 0131d5225b5..ba7c2ba618e 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -18,10 +18,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: dt2811 @@ -45,64 +41,60 @@ Configuration options: [4] - D/A 1 range (same choices) */ -#include <linux/interrupt.h> +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - -static const char *driver_name = "dt2811"; - static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, { - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25), - RANGE(0, 0.625) + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + UNI_RANGE(0.625) } }; static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = { 4, { - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - RANGE(-0.625, 0.625), - RANGE(-0.3125, 0.3125) + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) } }; static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = { 4, { - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - RANGE(-0.625, 0.625) + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) } }; static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = { 4, { - RANGE(0, 5), - RANGE(0, 0.5), - RANGE(0, 0.05), - RANGE(0, 0.01) + UNI_RANGE(5), + UNI_RANGE(0.5), + UNI_RANGE(0.05), + UNI_RANGE(0.01) } }; static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = { 4, { - RANGE(-2.5, 2.5), - RANGE(-0.25, 0.25), - RANGE(-0.025, 0.025), - RANGE(-0.005, 0.005) + BIP_RANGE(2.5), + BIP_RANGE(0.25), + BIP_RANGE(0.025), + BIP_RANGE(0.005) } }; static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { 4, { - RANGE(-5, 5), - RANGE(-0.5, 0.5), - RANGE(-0.05, 0.05), - RANGE(-0.01, 0.01) + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.01) } }; @@ -211,61 +203,6 @@ struct dt2811_board { const struct comedi_lrange *unip_5; }; -static const struct dt2811_board boardtypes[] = { - {"dt2811-pgh", - &range_dt2811_pgh_ai_5_bipolar, - &range_dt2811_pgh_ai_2_5_bipolar, - &range_dt2811_pgh_ai_5_unipolar, - }, - {"dt2811-pgl", - &range_dt2811_pgl_ai_5_bipolar, - &range_dt2811_pgl_ai_2_5_bipolar, - &range_dt2811_pgl_ai_5_unipolar, - }, -}; - -#define this_board ((const struct dt2811_board *)dev->board_ptr) - -static int dt2811_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2811_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2811 = { - .driver_name = "dt2811", - .module = THIS_MODULE, - .attach = dt2811_attach, - .detach = dt2811_detach, - .board_name = &boardtypes[0].name, - .num_names = ARRAY_SIZE(boardtypes), - .offset = sizeof(struct dt2811_board), -}; - -static int __init driver_dt2811_init_module(void) -{ - return comedi_driver_register(&driver_dt2811); -} - -static void __exit driver_dt2811_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2811); -} - -module_init(driver_dt2811_init_module); -module_exit(driver_dt2811_cleanup_module); - -static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -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_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2811_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int dt2811_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - enum { card_2811_pgh, card_2811_pgl }; struct dt2811_private { @@ -281,41 +218,103 @@ struct dt2811_private { unsigned int ao_readback[2]; }; -#define devpriv ((struct dt2811_private *)dev->private) - static const struct comedi_lrange *dac_range_types[] = { &range_bipolar5, &range_bipolar2_5, &range_unipolar5 }; -#define DT2811_TIMEOUT 5 +static int dt2811_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; -#if 0 -static irqreturn_t dt2811_interrupt(int irq, void *d) + status = inb(dev->iobase + DT2811_ADCSR); + if ((status & DT2811_ADBUSY) == 0) + return 0; + return -EBUSY; +} + +static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int lo, hi; - int data; - struct comedi_device *dev = d; + int chan = CR_CHAN(insn->chanspec); + int ret; + int i; + + for (i = 0; i < insn->n; i++) { + outb(chan, dev->iobase + DT2811_ADGCR); + + ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0); + if (ret) + return ret; - if (!dev->attached) { - comedi_error(dev, "spurious interrupt"); - return IRQ_HANDLED; + data[i] = inb(dev->iobase + DT2811_ADDATLO); + data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; + data[i] &= 0xfff; } - lo = inb(dev->iobase + DT2811_ADDATLO); - hi = inb(dev->iobase + DT2811_ADDATHI); + return i; +} + +static int dt2811_ao_insn(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; - data = lo + (hi << 8); + chan = CR_CHAN(insn->chanspec); - if (!(--devpriv->ntrig)) { - /* how to turn off acquisition */ - s->async->events |= COMEDI_SB_EOA; + for (i = 0; i < insn->n; i++) { + outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan); + outb((data[i] >> 8) & 0xff, + dev->iobase + DT2811_DADAT0HI + 2 * chan); + devpriv->ao_readback[chan] = data[i]; } - comedi_event(dev, s); - return IRQ_HANDLED; + + 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; +} + +static int dt2811_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + data[1] = inb(dev->iobase + DT2811_DIO); + + return insn->n; +} + +static int dt2811_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DT2811_DIO); + + data[1] = s->state; + + return insn->n; } -#endif /* options[0] Board base address @@ -337,28 +336,17 @@ static irqreturn_t dt2811_interrupt(int irq, void *d) 1 == bipolar 2.5V (-2.5V -- +2.5V) 2 == unipolar 5V (0V -- +5V) */ - static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - /* int i, irq; */ - /* unsigned long irqs; */ - /* long flags; */ - + /* int i; */ + const struct dt2811_board *board = comedi_board(dev); + struct dt2811_private *devpriv; int ret; struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - - printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase); - - if (!request_region(iobase, DT2811_SIZE, driver_name)) { - printk(KERN_ERR "I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - dev->board_name = this_board->name; + ret = comedi_request_region(dev, it->options[0], DT2811_SIZE); + if (ret) + return ret; #if 0 outb(0, dev->iobase + DT2811_ADCSR); @@ -367,52 +355,13 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) i = inb(dev->iobase + DT2811_ADDATHI); #endif -#if 0 - irq = it->options[1]; - if (irq < 0) { - save_flags(flags); - sti(); - irqs = probe_irq_on(); - - outb(DT2811_CLRERROR | DT2811_INTENB, - dev->iobase + DT2811_ADCSR); - outb(0, dev->iobase + DT2811_ADGCR); - - udelay(100); - - irq = probe_irq_off(irqs); - restore_flags(flags); - - /*outb(DT2811_CLRERROR|DT2811_INTENB, - dev->iobase+DT2811_ADCSR);*/ - - if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR) - printk(KERN_ERR "error probing irq (bad)\n"); - dev->irq = 0; - if (irq > 0) { - i = inb(dev->iobase + DT2811_ADDATLO); - i = inb(dev->iobase + DT2811_ADDATHI); - printk(KERN_INFO "(irq = %d)\n", irq); - ret = request_irq(irq, dt2811_interrupt, 0, - driver_name, dev); - if (ret < 0) - return -EIO; - dev->irq = irq; - } else if (irq == 0) { - printk(KERN_INFO "(no irq)\n"); - } else { - printk(KERN_ERR "( multiple irq's -- this is bad! )\n"); - } - } -#endif - - ret = alloc_subdevices(dev, 4); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - ret = alloc_private(dev, sizeof(struct dt2811_private)); - if (ret < 0) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; switch (it->options[2]) { case 0: @@ -457,7 +406,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) break; } - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* initialize the ADC subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -467,17 +416,17 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) switch (it->options[3]) { case 0: default: - s->range_table = this_board->bip_5; + s->range_table = board->bip_5; break; case 1: - s->range_table = this_board->bip_2_5; + s->range_table = board->bip_2_5; break; case 2: - s->range_table = this_board->unip_5; + s->range_table = board->unip_5; break; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -489,7 +438,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) 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 = dev->subdevices + 2; + s = &dev->subdevices[2]; /* di subdevice */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -498,7 +447,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 1; s->range_table = &range_digital; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* do subdevice */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -511,131 +460,30 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int dt2811_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor); - - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, DT2811_SIZE); - - return 0; -} - -static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - int timeout = DT2811_TIMEOUT; - int i; - - for (i = 0; i < insn->n; i++) { - outb(chan, dev->iobase + DT2811_ADGCR); - - while (timeout - && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY) - timeout--; - if (!timeout) - return -ETIME; - - data[i] = inb(dev->iobase + DT2811_ADDATLO); - data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8; - data[i] &= 0xfff; - } - - return i; -} - -#if 0 -/* Wow. This is code from the Comedi stone age. But it hasn't been - * replaced, so I'll let it stay. */ -int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig) -{ - struct comedi_device *dev = comedi_devices + minor; - - if (adtrig->n < 1) - return 0; - dev->curadchan = adtrig->chan; - switch (dev->i_admode) { - case COMEDI_MDEMAND: - dev->ntrig = adtrig->n - 1; - /* not necessary */ - /*printk("dt2811: AD soft trigger\n"); */ - /*outb(DT2811_CLRERROR|DT2811_INTENB, - dev->iobase+DT2811_ADCSR); */ - outb(dev->curadchan, dev->iobase + DT2811_ADGCR); - do_gettimeofday(&trigtime); - break; - case COMEDI_MCONTS: - dev->ntrig = adtrig->n; - break; - } - - return 0; -} -#endif - -static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - 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, - dev->iobase + DT2811_DADAT0HI + 2 * chan); - devpriv->ao_readback[chan] = data[i]; - } - - return i; -} - -static int dt2811_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i; - int chan; - - chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; - - return i; -} - -static int dt2811_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = inb(dev->iobase + DT2811_DIO); - - return 2; -} - -static int dt2811_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outb(s->state, dev->iobase + DT2811_DIO); - - data[1] = s->state; +static const struct dt2811_board boardtypes[] = { + { + .name = "dt2811-pgh", + .bip_5 = &range_dt2811_pgh_ai_5_bipolar, + .bip_2_5 = &range_dt2811_pgh_ai_2_5_bipolar, + .unip_5 = &range_dt2811_pgh_ai_5_unipolar, + }, { + .name = "dt2811-pgl", + .bip_5 = &range_dt2811_pgl_ai_5_bipolar, + .bip_2_5 = &range_dt2811_pgl_ai_2_5_bipolar, + .unip_5 = &range_dt2811_pgl_ai_5_unipolar, + }, +}; - return 2; -} +static struct comedi_driver dt2811_driver = { + .driver_name = "dt2811", + .module = THIS_MODULE, + .attach = dt2811_attach, + .detach = comedi_legacy_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct dt2811_board), +}; +module_comedi_driver(dt2811_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index 1c6248cf592..904c9f0e4af 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt2814 @@ -39,12 +34,14 @@ a power of 10, from 1 to 10^7, of which only 3 or 4 are useful. In addition, the clock does not seem to be very accurate. */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/delay.h> +#include "comedi_fc.h" + #define DT2814_SIZE 2 #define DT2814_CSR 0 @@ -60,65 +57,44 @@ addition, the clock does not seem to be very accurate. #define DT2814_ENB 0x10 #define DT2814_CHANMASK 0x0f -static int dt2814_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2814_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2814 = { - .driver_name = "dt2814", - .module = THIS_MODULE, - .attach = dt2814_attach, - .detach = dt2814_detach, -}; - -static int __init driver_dt2814_init_module(void) -{ - return comedi_driver_register(&driver_dt2814); -} - -static void __exit driver_dt2814_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2814); -} - -module_init(driver_dt2814_init_module); -module_exit(driver_dt2814_cleanup_module); - -static irqreturn_t dt2814_interrupt(int irq, void *dev); - struct dt2814_private { int ntrig; int curadchan; }; -#define devpriv ((struct dt2814_private *)dev->private) - #define DT2814_TIMEOUT 10 #define DT2814_MAX_SPEED 100000 /* Arbitrary 10 khz limit */ +static int dt2814_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inb(dev->iobase + DT2814_CSR); + if (status & DT2814_FINISH) + return 0; + return -EBUSY; +} + static int dt2814_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i, hi, lo; + int n, hi, lo; int chan; - int status = 0; + int ret; for (n = 0; n < insn->n; n++) { chan = CR_CHAN(insn->chanspec); outb(chan, dev->iobase + DT2814_CSR); - for (i = 0; i < DT2814_TIMEOUT; i++) { - status = inb(dev->iobase + DT2814_CSR); - printk(KERN_INFO "dt2814: status: %02x\n", status); - udelay(10); - if (status & DT2814_FINISH) - break; - } - if (i >= DT2814_TIMEOUT) { - printk(KERN_INFO "dt2814: status: %02x\n", status); - return -ETIMEDOUT; - } + + ret = comedi_timeout(dev, s, insn, dt2814_ai_eoc, 0); + if (ret) + return ret; hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); @@ -152,88 +128,51 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; + unsigned int arg; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, 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_NONE); - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + if (err) + return 1; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 2a : make sure trigger sources are unique */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_is_unique(cmd->stop_src); - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + /* Step 2b : and mutually compatible */ if (err) - return 1; + return 2; - /* step 2: make sure trigger sources are - * unique and mutually compatible */ + /* Step 3: check if arguments are trivially valid */ - /* note that mutual compatibility is not an issue here */ - if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (err) - return 2; + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 1000000000); + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + DT2814_MAX_SPEED); - /* step 3: make sure arguments are trivially compatible */ + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->scan_begin_arg > 1000000000) { - cmd->scan_begin_arg = 1000000000; - err++; - } - if (cmd->scan_begin_arg < DT2814_MAX_SPEED) { - cmd->scan_begin_arg = DT2814_MAX_SPEED; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg < 2) { - cmd->stop_arg = 2; - err++; - } - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + if (cmd->stop_src == TRIG_COUNT) + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 2); + else /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); if (err) return 3; /* step 4: fix up any arguments */ - tmp = cmd->scan_begin_arg; - dt2814_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + dt2814_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); if (err) return 4; @@ -243,6 +182,7 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev, static int dt2814_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct dt2814_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int chan; int trigvar; @@ -260,111 +200,12 @@ static int dt2814_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } -static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - int i, irq; - int ret; - struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: dt2814: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, DT2814_SIZE, "dt2814")) { - printk(KERN_ERR "I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - dev->board_name = "dt2814"; - - outb(0, dev->iobase + DT2814_CSR); - udelay(100); - if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) { - printk(KERN_ERR "reset error (fatal)\n"); - return -EIO; - } - i = inb(dev->iobase + DT2814_DATA); - i = inb(dev->iobase + DT2814_DATA); - - irq = it->options[1]; -#if 0 - if (irq < 0) { - save_flags(flags); - sti(); - irqs = probe_irq_on(); - - outb(0, dev->iobase + DT2814_CSR); - - udelay(100); - - irq = probe_irq_off(irqs); - restore_flags(flags); - if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) - printk(KERN_DEBUG "error probing irq (bad)\n"); - - - i = inb(dev->iobase + DT2814_DATA); - i = inb(dev->iobase + DT2814_DATA); - } -#endif - dev->irq = 0; - if (irq > 0) { - if (request_irq(irq, dt2814_interrupt, 0, "dt2814", dev)) { - printk(KERN_WARNING "(irq %d unavailable)\n", irq); - } else { - printk(KERN_INFO "( irq = %d )\n", irq); - dev->irq = irq; - } - } else if (irq == 0) { - printk(KERN_WARNING "(no irq)\n"); - } else { -#if 0 - printk(KERN_DEBUG "(probe returned multiple irqs--bad)\n"); -#else - printk(KERN_WARNING "(irq probe not implemented)\n"); -#endif - } - - ret = alloc_subdevices(dev, 1); - if (ret < 0) - return ret; - - ret = alloc_private(dev, sizeof(struct dt2814_private)); - if (ret < 0) - return ret; - - s = dev->subdevices + 0; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - s->n_chan = 16; /* XXX */ - s->len_chanlist = 1; - s->insn_read = dt2814_ai_insn_read; - s->do_cmd = dt2814_ai_cmd; - s->do_cmdtest = dt2814_ai_cmdtest; - s->maxdata = 0xfff; - s->range_table = &range_unknown; /* XXX */ - - return 0; -} - -static int dt2814_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: dt2814: remove\n", dev->minor); - - if (dev->irq) - free_irq(dev->irq, dev); - - if (dev->iobase) - release_region(dev->iobase, DT2814_SIZE); - - return 0; -} - static irqreturn_t dt2814_interrupt(int irq, void *d) { int lo, hi; struct comedi_device *dev = d; - struct comedi_subdevice *s; + struct dt2814_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; int data; if (!dev->attached) { @@ -372,8 +213,6 @@ static irqreturn_t dt2814_interrupt(int irq, void *d) return IRQ_HANDLED; } - s = dev->subdevices + 0; - hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); @@ -399,6 +238,67 @@ static irqreturn_t dt2814_interrupt(int irq, void *d) return IRQ_HANDLED; } +static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct dt2814_private *devpriv; + struct comedi_subdevice *s; + int ret; + int i; + + ret = comedi_request_region(dev, it->options[0], DT2814_SIZE); + if (ret) + return ret; + + outb(0, dev->iobase + DT2814_CSR); + udelay(100); + if (inb(dev->iobase + DT2814_CSR) & DT2814_ERR) { + dev_err(dev->class_dev, "reset error (fatal)\n"); + return -EIO; + } + i = inb(dev->iobase + DT2814_DATA); + i = inb(dev->iobase + DT2814_DATA); + + if (it->options[1]) { + ret = request_irq(it->options[1], dt2814_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; + } + + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; /* XXX */ + s->insn_read = dt2814_ai_insn_read; + s->maxdata = 0xfff; + s->range_table = &range_unknown; /* XXX */ + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; + s->do_cmd = dt2814_ai_cmd; + s->do_cmdtest = dt2814_ai_cmdtest; + } + + return 0; +} + +static struct comedi_driver dt2814_driver = { + .driver_name = "dt2814", + .module = THIS_MODULE, + .attach = dt2814_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(dt2814_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index 4155da43fd5..b9ac4ed8bab 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt2815 @@ -56,70 +51,40 @@ Configuration options: [12] - Analog output 7 range configuration (same options) */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/delay.h> -static const struct comedi_lrange - range_dt2815_ao_32_current = {1, {RANGE_mA(0, 32)} }; - -static const struct comedi_lrange - range_dt2815_ao_20_current = {1, {RANGE_mA(4, 20)} }; - #define DT2815_SIZE 2 #define DT2815_DATA 0 #define DT2815_STATUS 1 -static int dt2815_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2815_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2815 = { - .driver_name = "dt2815", - .module = THIS_MODULE, - .attach = dt2815_attach, - .detach = dt2815_detach, -}; - -static int __init driver_dt2815_init_module(void) -{ - return comedi_driver_register(&driver_dt2815); -} - -static void __exit driver_dt2815_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2815); -} - -module_init(driver_dt2815_init_module); -module_exit(driver_dt2815_cleanup_module); - -static void dt2815_free_resources(struct comedi_device *dev); - struct dt2815_private { const struct comedi_lrange *range_type_list[8]; unsigned int ao_readback[8]; }; -#define devpriv ((struct dt2815_private *)dev->private) - -static int dt2815_wait_for_status(struct comedi_device *dev, int status) +static int dt2815_ao_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int i; + unsigned int status; - for (i = 0; i < 100; i++) { - if (inb(dev->iobase + DT2815_STATUS) == status) - break; - } - return status; + status = inb(dev->iobase + DT2815_STATUS); + if (status == context) + return 0; + return -EBUSY; } static int dt2815_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct dt2815_private *devpriv = dev->private; int i; int chan = CR_CHAN(insn->chanspec); @@ -132,30 +97,26 @@ static int dt2815_ao_insn_read(struct comedi_device *dev, static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct dt2815_private *devpriv = dev->private; int i; int chan = CR_CHAN(insn->chanspec); - unsigned int status; unsigned int lo, hi; + int ret; for (i = 0; i < insn->n; i++) { lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01; hi = (data[i] & 0xff0) >> 4; - status = dt2815_wait_for_status(dev, 0x00); - if (status != 0) { - printk(KERN_WARNING "dt2815: failed to write low byte " - "on %d reason %x\n", chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x00); + if (ret) + return ret; outb(lo, dev->iobase + DT2815_DATA); - status = dt2815_wait_for_status(dev, 0x10); - if (status != 0x10) { - printk(KERN_WARNING "dt2815: failed to write high byte " - "on %d reason %x\n", chan, status); - return -EBUSY; - } + ret = comedi_timeout(dev, s, insn, dt2815_ao_status, 0x10); + if (ret) + return ret; + devpriv->ao_readback[chan] = data[i]; } return i; @@ -187,27 +148,25 @@ static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + struct dt2815_private *devpriv; struct comedi_subdevice *s; int i; const struct comedi_lrange *current_range_type, *voltage_range_type; - unsigned long iobase; + int ret; - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: dt2815: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, DT2815_SIZE, "dt2815")) { - printk(KERN_WARNING "I/O port conflict\n"); - return -EIO; - } + ret = comedi_request_region(dev, it->options[0], DT2815_SIZE); + if (ret) + return ret; - dev->iobase = iobase; - dev->board_name = "dt2815"; + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - if (alloc_private(dev, sizeof(struct dt2815_private)) < 0) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - s = dev->subdevices; + s = &dev->subdevices[0]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -218,7 +177,7 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table_list = devpriv->range_type_list; current_range_type = (it->options[3]) - ? &range_dt2815_ao_20_current : &range_dt2815_ao_32_current; + ? &range_4_20mA : &range_0_32mA; voltage_range_type = (it->options[2]) ? &range_bipolar5 : &range_unipolar5; for (i = 0; i < 8; i++) { @@ -238,12 +197,13 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) unsigned int program; program = (it->options[4] & 0x3) << 3 | 0x7; outb(program, dev->iobase + DT2815_DATA); - printk(KERN_INFO ", program: 0x%x (@t=%d)\n", - program, i); + dev_dbg(dev->class_dev, "program: 0x%x (@t=%d)\n", + program, i); break; } else if (status != 0x00) { - printk(KERN_WARNING "dt2815: unexpected status 0x%x " - "(@t=%d)\n", status, i); + dev_dbg(dev->class_dev, + "unexpected status 0x%x (@t=%d)\n", + status, i); if (status & 0x60) outb(0x00, dev->iobase + DT2815_STATUS); } @@ -252,20 +212,13 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static void dt2815_free_resources(struct comedi_device *dev) -{ - if (dev->iobase) - release_region(dev->iobase, DT2815_SIZE); -} - -static int dt2815_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: dt2815: remove\n", dev->minor); - - dt2815_free_resources(dev); - - return 0; -} +static struct comedi_driver dt2815_driver = { + .driver_name = "dt2815", + .module = THIS_MODULE, + .attach = dt2815_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(dt2815_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c index 99c1584153d..bf589936e54 100644 --- a/drivers/staging/comedi/drivers/dt2817.c +++ b/drivers/staging/comedi/drivers/dt2817.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt2817 @@ -38,62 +33,36 @@ Configuration options: [0] - I/O port base base address */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - #define DT2817_SIZE 5 #define DT2817_CR 0 #define DT2817_DATA 1 -static int dt2817_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt2817_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt2817 = { - .driver_name = "dt2817", - .module = THIS_MODULE, - .attach = dt2817_attach, - .detach = dt2817_detach, -}; - -static int __init driver_dt2817_init_module(void) -{ - return comedi_driver_register(&driver_dt2817); -} - -static void __exit driver_dt2817_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt2817); -} - -module_init(driver_dt2817_init_module); -module_exit(driver_dt2817_cleanup_module); - static int dt2817_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int mask; - int chan; - int oe = 0; - - if (insn->n != 1) - return -EINVAL; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int oe = 0; + unsigned int mask; + int ret; - chan = CR_CHAN(insn->chanspec); if (chan < 8) - mask = 0xff; + mask = 0x000000ff; else if (chan < 16) - mask = 0xff00; + mask = 0x0000ff00; else if (chan < 24) - mask = 0xff0000; + mask = 0x00ff0000; else mask = 0xff000000; - if (data[0]) - s->io_bits |= mask; - else - s->io_bits &= ~mask; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; if (s->io_bits & 0x000000ff) oe |= 0x1; @@ -106,65 +75,54 @@ static int dt2817_dio_insn_config(struct comedi_device *dev, outb(oe, dev->iobase + DT2817_CR); - return 1; + return insn->n; } static int dt2817_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int changed; - - /* It's questionable whether it is more important in - * a driver like this to be deterministic or fast. - * We choose fast. */ - - if (data[0]) { - changed = s->state; - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - changed ^= s->state; - changed &= s->io_bits; - if (changed & 0x000000ff) - outb(s->state & 0xff, dev->iobase + DT2817_DATA + 0); - if (changed & 0x0000ff00) - outb((s->state >> 8) & 0xff, - dev->iobase + DT2817_DATA + 1); - if (changed & 0x00ff0000) - outb((s->state >> 16) & 0xff, - dev->iobase + DT2817_DATA + 2); - if (changed & 0xff000000) - outb((s->state >> 24) & 0xff, - dev->iobase + DT2817_DATA + 3); + unsigned long iobase = dev->iobase + DT2817_DATA; + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x000000ff) + outb(s->state & 0xff, iobase + 0); + if (mask & 0x0000ff00) + outb((s->state >> 8) & 0xff, iobase + 1); + if (mask & 0x00ff0000) + outb((s->state >> 16) & 0xff, iobase + 2); + if (mask & 0xff000000) + outb((s->state >> 24) & 0xff, iobase + 3); } - data[1] = inb(dev->iobase + DT2817_DATA + 0); - data[1] |= (inb(dev->iobase + DT2817_DATA + 1) << 8); - data[1] |= (inb(dev->iobase + DT2817_DATA + 2) << 16); - data[1] |= (inb(dev->iobase + DT2817_DATA + 3) << 24); - return 2; + val = inb(iobase + 0); + val |= (inb(iobase + 1) << 8); + val |= (inb(iobase + 2) << 16); + val |= (inb(iobase + 3) << 24); + + data[1] = val; + + return insn->n; } static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it) { int ret; struct comedi_subdevice *s; - unsigned long iobase; - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: dt2817: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, DT2817_SIZE, "dt2817")) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - dev->board_name = "dt2817"; + ret = comedi_request_region(dev, it->options[0], DT2817_SIZE); + if (ret) + return ret; - ret = alloc_subdevices(dev, 1); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 1); + if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->n_chan = 32; s->type = COMEDI_SUBD_DIO; @@ -177,20 +135,16 @@ static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->state = 0; outb(0, dev->iobase + DT2817_CR); - printk(KERN_INFO "\n"); - return 0; } -static int dt2817_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: dt2817: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, DT2817_SIZE); - - return 0; -} +static struct comedi_driver dt2817_driver = { + .driver_name = "dt2817", + .module = THIS_MODULE, + .attach = dt2817_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(dt2817_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 8cea9dca3d7..c2a66dcf99f 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt282x @@ -56,17 +51,18 @@ Notes: be fixed to check for this situation and return an error. */ +#include <linux/module.h> #include "../comedidev.h" +#include <linux/delay.h> #include <linux/gfp.h> -#include <linux/ioport.h> #include <linux/interrupt.h> +#include <linux/io.h> + #include <asm/dma.h> -#include "comedi_fc.h" -#define DEBUG +#include "comedi_fc.h" -#define DT2821_TIMEOUT 100 /* 500 us */ #define DT2821_SIZE 0x10 /* @@ -157,55 +153,55 @@ Notes: static const struct comedi_lrange range_dt282x_ai_lo_bipolar = { 4, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25) + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) } }; static const struct comedi_lrange range_dt282x_ai_lo_unipolar = { 4, { - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25) + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) } }; static const struct comedi_lrange range_dt282x_ai_5_bipolar = { 4, { - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25), - RANGE(-0.625, 0.625) + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) } }; static const struct comedi_lrange range_dt282x_ai_5_unipolar = { 4, { - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25), - RANGE(0, 0.625), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + UNI_RANGE(0.625) } }; static const struct comedi_lrange range_dt282x_ai_hi_bipolar = { 4, { - RANGE(-10, 10), - RANGE(-1, 1), - RANGE(-0.1, 0.1), - RANGE(-0.02, 0.02) + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02) } }; static const struct comedi_lrange range_dt282x_ai_hi_unipolar = { 4, { - RANGE(0, 10), - RANGE(0, 1), - RANGE(0, 0.1), - RANGE(0, 0.02) + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) } }; @@ -220,138 +216,6 @@ struct dt282x_board { int dabits; }; -static const struct dt282x_board boardtypes[] = { - {.name = "dt2821", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 20000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2821-f", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 6500, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2821-g", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 4000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2823", - .adbits = 16, - .adchan_se = 0, - .adchan_di = 4, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 2, - .dabits = 16, - }, - {.name = "dt2824-pgh", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 20000, - .ispgl = 0, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt2824-pgl", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 20000, - .ispgl = 1, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt2825", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 20000, - .ispgl = 1, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2827", - .adbits = 16, - .adchan_se = 0, - .adchan_di = 4, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2828", - .adbits = 12, - .adchan_se = 4, - .adchan_di = 0, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt2829", - .adbits = 16, - .adchan_se = 8, - .adchan_di = 0, - .ai_speed = 33250, - .ispgl = 0, - .dachan = 2, - .dabits = 16, - }, - {.name = "dt21-ez", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt23-ez", - .adbits = 16, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt24-ez", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 10000, - .ispgl = 0, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt24-ez-pgl", - .adbits = 12, - .adchan_se = 16, - .adchan_di = 8, - .ai_speed = 10000, - .ispgl = 1, - .dachan = 0, - .dabits = 0, - }, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct dt282x_board)) -#define this_board ((const struct dt282x_board *)dev->board_ptr) - struct dt282x_private { int ad_2scomp; /* we have 2's comp jumper set */ int da0_2scomp; /* same, for DAC0 */ @@ -359,7 +223,7 @@ struct dt282x_private { const struct comedi_lrange *darangelist[2]; - short ao[2]; + unsigned short ao[2]; volatile int dacsr; /* software copies of registers */ volatile int adcsr; @@ -370,7 +234,7 @@ struct dt282x_private { struct { int chan; - short *buf; /* DMA buffer */ + unsigned short *buf; /* DMA buffer */ volatile int size; /* size of current transfer */ } dma[2]; int dma_maxsize; /* max size of DMA transfer (in bytes) */ @@ -379,64 +243,11 @@ struct dt282x_private { int dma_dir; }; -#define devpriv ((struct dt282x_private *)dev->private) -#define boardtype (*(const struct dt282x_board *)dev->board_ptr) - /* * Some useless abstractions */ #define chan_to_DAC(a) ((a)&1) -#define update_dacsr(a) outw(devpriv->dacsr|(a), dev->iobase+DT2821_DACSR) -#define update_adcsr(a) outw(devpriv->adcsr|(a), dev->iobase+DT2821_ADCSR) -#define mux_busy() (inw(dev->iobase+DT2821_ADCSR)&DT2821_MUXBUSY) -#define ad_done() (inw(dev->iobase+DT2821_ADCSR)&DT2821_ADDONE) -#define update_supcsr(a) outw(devpriv->supcsr|(a), dev->iobase+DT2821_SUPCSR) - -/* - * danger! macro abuse... a is the expression to wait on, and b is - * the statement(s) to execute if it doesn't happen. - */ -#define wait_for(a, b) \ - do { \ - int _i; \ - for (_i = 0; _i < DT2821_TIMEOUT; _i++) { \ - if (a) { \ - _i = 0; \ - break; \ - } \ - udelay(5); \ - } \ - if (_i) \ - b \ - } while (0) - -static int dt282x_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt282x_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt282x = { - .driver_name = "dt282x", - .module = THIS_MODULE, - .attach = dt282x_attach, - .detach = dt282x_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct dt282x_board), -}; - -static int __init driver_dt282x_init_module(void) -{ - return comedi_driver_register(&driver_dt282x); -} - -static void __exit driver_dt282x_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dt282x); -} -module_init(driver_dt282x_init_module); -module_exit(driver_dt282x_cleanup_module); - -static void free_resources(struct comedi_device *dev); static int prep_ai_dma(struct comedi_device *dev, int chan, int size); static int prep_ao_dma(struct comedi_device *dev, int chan, int size); static int dt282x_ai_cancel(struct comedi_device *dev, @@ -448,16 +259,18 @@ static void dt282x_disable_dma(struct comedi_device *dev); static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2); -static void dt282x_munge(struct comedi_device *dev, short *buf, +static void dt282x_munge(struct comedi_device *dev, unsigned short *buf, unsigned int nbytes) { + const struct dt282x_board *board = comedi_board(dev); + struct dt282x_private *devpriv = dev->private; unsigned int i; - unsigned short mask = (1 << boardtype.adbits) - 1; - unsigned short sign = 1 << (boardtype.adbits - 1); + unsigned short mask = (1 << board->adbits) - 1; + unsigned short sign = 1 << (board->adbits - 1); int n; if (devpriv->ad_2scomp) - sign = 1 << (boardtype.adbits - 1); + sign = 1 << (board->adbits - 1); else sign = 0; @@ -470,15 +283,16 @@ static void dt282x_munge(struct comedi_device *dev, short *buf, static void dt282x_ao_dma_interrupt(struct comedi_device *dev) { + struct dt282x_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->write_subdev; void *ptr; int size; int i; - struct comedi_subdevice *s = dev->subdevices + 1; - update_supcsr(DT2821_CLRDMADNE); + outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR); if (!s->async->prealloc_buf) { - printk(KERN_ERR "async->data disappeared. dang!\n"); + dev_err(dev->class_dev, "no buffer in %s\n", __func__); return; } @@ -491,8 +305,7 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev) size = cfc_read_array_from_buffer(s, ptr, devpriv->dma_maxsize); if (size == 0) { - printk(KERN_ERR "dt282x: AO underrun\n"); - dt282x_ao_cancel(dev, s); + dev_err(dev->class_dev, "AO underrun\n"); s->async->events |= COMEDI_CB_OVERFLOW; return; } @@ -502,16 +315,17 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev) static void dt282x_ai_dma_interrupt(struct comedi_device *dev) { + struct dt282x_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; void *ptr; int size; int i; int ret; - struct comedi_subdevice *s = dev->subdevices; - update_supcsr(DT2821_CLRDMADNE); + outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR); if (!s->async->prealloc_buf) { - printk(KERN_ERR "async->data disappeared. dang!\n"); + dev_err(dev->class_dev, "no buffer in %s\n", __func__); return; } @@ -526,17 +340,16 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) dt282x_munge(dev, ptr, size); ret = cfc_write_array_to_buffer(s, ptr, size); if (ret != size) { - dt282x_ai_cancel(dev, s); + s->async->events |= COMEDI_CB_OVERFLOW; return; } devpriv->nread -= size / 2; if (devpriv->nread < 0) { - printk(KERN_INFO "dt282x: off by one\n"); + dev_info(dev->class_dev, "nread off by one\n"); devpriv->nread = 0; } if (!devpriv->nread) { - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_EOA; return; } @@ -545,7 +358,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) /* XXX probably wrong */ if (!devpriv->ntrig) { devpriv->supcsr &= ~(DT2821_DDMA); - update_supcsr(0); + outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR); } #endif /* restart the channel */ @@ -554,6 +367,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n) { + struct dt282x_private *devpriv = dev->private; int dma_chan; unsigned long dma_ptr; unsigned long flags; @@ -585,6 +399,7 @@ static int prep_ai_dma(struct comedi_device *dev, int dma_index, int n) static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n) { + struct dt282x_private *devpriv = dev->private; int dma_chan; unsigned long dma_ptr; unsigned long flags; @@ -608,8 +423,9 @@ static int prep_ao_dma(struct comedi_device *dev, int dma_index, int n) static irqreturn_t dt282x_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s; - struct comedi_subdevice *s_ao; + struct dt282x_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_subdevice *s_ao = dev->write_subdev; unsigned int supcsr, adcsr, dacsr; int handled = 0; @@ -618,8 +434,6 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) return IRQ_HANDLED; } - s = dev->subdevices + 0; - s_ao = dev->subdevices + 1; adcsr = inw(dev->iobase + DT2821_ADCSR); dacsr = inw(dev->iobase + DT2821_DACSR); supcsr = inw(dev->iobase + DT2821_SUPCSR); @@ -633,35 +447,26 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) if (adcsr & DT2821_ADERR) { if (devpriv->nread != 0) { comedi_error(dev, "A/D error"); - dt282x_ai_cancel(dev, s); s->async->events |= COMEDI_CB_ERROR; } handled = 1; } if (dacsr & DT2821_DAERR) { -#if 0 - static int warn = 5; - if (--warn <= 0) { - disable_irq(dev->irq); - printk(KERN_INFO "disabling irq\n"); - } -#endif comedi_error(dev, "D/A error"); - dt282x_ao_cancel(dev, s_ao); - s->async->events |= COMEDI_CB_ERROR; + s_ao->async->events |= COMEDI_CB_ERROR; handled = 1; } #if 0 if (adcsr & DT2821_ADDONE) { int ret; - short data; + unsigned short data; - data = (short)inw(dev->iobase + DT2821_ADDAT); - data &= (1 << boardtype.adbits) - 1; + data = inw(dev->iobase + DT2821_ADDAT); + data &= (1 << board->adbits) - 1; if (devpriv->ad_2scomp) - data ^= 1 << (boardtype.adbits - 1); - ret = comedi_buf_put(s->async, data); + data ^= 1 << (board->adbits - 1); + ret = comedi_buf_put(s, data); if (ret == 0) s->async->events |= COMEDI_CB_OVERFLOW; @@ -671,20 +476,22 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) s->async->events |= COMEDI_CB_EOA; } else { if (supcsr & DT2821_SCDN) - update_supcsr(DT2821_STRIG); + outw(devpriv->supcsr | DT2821_STRIG, + dev->iobase + DT2821_SUPCSR); } handled = 1; } #endif - comedi_event(dev, s); - /* printk("adcsr=0x%02x dacsr-0x%02x supcsr=0x%02x\n", - adcsr, dacsr, supcsr); */ + cfc_handle_events(dev, s); + cfc_handle_events(dev, s_ao); + return IRQ_RETVAL(handled); } static void dt282x_load_changain(struct comedi_device *dev, int n, unsigned int *chanlist) { + struct dt282x_private *devpriv = dev->private; unsigned int i; unsigned int chan, range; @@ -692,11 +499,35 @@ static void dt282x_load_changain(struct comedi_device *dev, int n, for (i = 0; i < n; i++) { chan = CR_CHAN(chanlist[i]); range = CR_RANGE(chanlist[i]); - update_adcsr((range << 4) | (chan)); + outw(devpriv->adcsr | (range << 4) | chan, + dev->iobase + DT2821_ADCSR); } outw(n - 1, dev->iobase + DT2821_CHANCSR); } +static int dt282x_ai_timeout(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + DT2821_ADCSR); + switch (context) { + case DT2821_MUXBUSY: + if ((status & DT2821_MUXBUSY) == 0) + return 0; + break; + case DT2821_ADDONE: + if (status & DT2821_ADDONE) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + /* * Performs a single A/D conversion. * - Put channel/gain into channel-gain list @@ -707,27 +538,36 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + const struct dt282x_board *board = comedi_board(dev); + struct dt282x_private *devpriv = dev->private; + int ret; int i; /* XXX should we really be enabling the ad clock here? */ devpriv->adcsr = DT2821_ADCLK; - update_adcsr(0); + outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); dt282x_load_changain(dev, 1, &insn->chanspec); - update_supcsr(DT2821_PRLD); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; for (i = 0; i < insn->n; i++) { - update_supcsr(DT2821_STRIG); - wait_for(ad_done(), comedi_error(dev, "timeout\n"); - return -ETIME;); + outw(devpriv->supcsr | DT2821_STRIG, + dev->iobase + DT2821_SUPCSR); + + ret = comedi_timeout(dev, s, insn, dt282x_ai_timeout, + DT2821_ADDONE); + if (ret) + return ret; data[i] = inw(dev->iobase + - DT2821_ADDAT) & ((1 << boardtype.adbits) - 1); + DT2821_ADDAT) & ((1 << board->adbits) - 1); if (devpriv->ad_2scomp) - data[i] ^= (1 << (boardtype.adbits - 1)); + data[i] ^= (1 << (board->adbits - 1)); } return i; @@ -736,100 +576,56 @@ static int dt282x_ai_insn_read(struct comedi_device *dev, 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); int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + unsigned int arg; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + 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 2: make sure trigger sources are unique - * and mutually compatible - */ + /* 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->stop_src); - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } if (cmd->scan_begin_src == TRIG_FOLLOW) { /* internal trigger */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); } else { /* external trigger */ /* should be level/edge, hi/lo specification here */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - } - if (cmd->convert_arg < 4000) { - /* XXX board dependent */ - cmd->convert_arg = 4000; - err++; + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); } + + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000); + #define SLOWEST_TIMER (250*(1<<15)*255) - if (cmd->convert_arg > SLOWEST_TIMER) { - cmd->convert_arg = SLOWEST_TIMER; - err++; - } - if (cmd->convert_arg < this_board->ai_speed) { - cmd->convert_arg = this_board->ai_speed; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER); + 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_arg != 0) { - cmd->stop_arg = 0; - err++; - } + } else { /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -837,10 +633,9 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - tmp = cmd->convert_arg; - dt282x_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); if (err) return 4; @@ -850,8 +645,11 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct dt282x_board *board = comedi_board(dev); + struct dt282x_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int timer; + int ret; if (devpriv->usedma == 0) { comedi_error(dev, @@ -862,8 +660,8 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) dt282x_disable_dma(dev); - if (cmd->convert_arg < this_board->ai_speed) - cmd->convert_arg = this_board->ai_speed; + if (cmd->convert_arg < board->ai_speed) + cmd->convert_arg = board->ai_speed; timer = dt282x_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST); outw(timer, dev->iobase + DT2821_TMRCTR); @@ -874,7 +672,8 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* external trigger */ devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS0 | DT2821_DS1; } - update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT); + outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_ADCINIT, + dev->iobase + DT2821_SUPCSR); devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg; devpriv->nread = devpriv->ntrig; @@ -885,7 +684,7 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (devpriv->ntrig) { prep_ai_dma(dev, 1, 0); devpriv->supcsr |= DT2821_DDMA; - update_supcsr(0); + outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR); } devpriv->adcsr = 0; @@ -893,16 +692,19 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist); devpriv->adcsr = DT2821_ADCLK | DT2821_IADDONE; - update_adcsr(0); + outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); - update_supcsr(DT2821_PRLD); - wait_for(!mux_busy(), comedi_error(dev, "timeout\n"); return -ETIME;); + outw(devpriv->supcsr | DT2821_PRLD, dev->iobase + DT2821_SUPCSR); + ret = comedi_timeout(dev, s, NULL, dt282x_ai_timeout, DT2821_MUXBUSY); + if (ret) + return ret; if (cmd->scan_begin_src == TRIG_FOLLOW) { - update_supcsr(DT2821_STRIG); + outw(devpriv->supcsr | DT2821_STRIG, + dev->iobase + DT2821_SUPCSR); } else { devpriv->supcsr |= DT2821_XTRIG; - update_supcsr(0); + outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR); } return 0; @@ -910,6 +712,8 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static void dt282x_disable_dma(struct comedi_device *dev) { + struct dt282x_private *devpriv = dev->private; + if (devpriv->usedma) { disable_dma(devpriv->dma[0].chan); disable_dma(devpriv->dma[1].chan); @@ -919,13 +723,15 @@ static void dt282x_disable_dma(struct comedi_device *dev) static int dt282x_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct dt282x_private *devpriv = dev->private; + dt282x_disable_dma(dev); devpriv->adcsr = 0; - update_adcsr(0); + outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR); devpriv->supcsr = 0; - update_supcsr(DT2821_ADCINIT); + outw(devpriv->supcsr | DT2821_ADCINIT, dev->iobase + DT2821_SUPCSR); return 0; } @@ -971,6 +777,8 @@ 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; + data[0] = devpriv->ao[CR_CHAN(insn->chanspec)]; return 1; @@ -980,12 +788,14 @@ static int dt282x_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - short d; + const struct dt282x_board *board = comedi_board(dev); + struct dt282x_private *devpriv = dev->private; + unsigned short d; unsigned int chan; chan = CR_CHAN(insn->chanspec); d = data[0]; - d &= (1 << boardtype.dabits) - 1; + d &= (1 << board->dabits) - 1; devpriv->ao[chan] = d; devpriv->dacsr |= DT2821_SSEL; @@ -994,18 +804,18 @@ static int dt282x_ao_insn_write(struct comedi_device *dev, /* select channel */ devpriv->dacsr |= DT2821_YSEL; if (devpriv->da0_2scomp) - d ^= (1 << (boardtype.dabits - 1)); + d ^= (1 << (board->dabits - 1)); } else { devpriv->dacsr &= ~DT2821_YSEL; if (devpriv->da1_2scomp) - d ^= (1 << (boardtype.dabits - 1)); + d ^= (1 << (board->dabits - 1)); } - update_dacsr(0); + outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); outw(d, dev->iobase + DT2821_DADAT); - update_supcsr(DT2821_DACON); + outw(devpriv->supcsr | DT2821_DACON, dev->iobase + DT2821_SUPCSR); return 1; } @@ -1014,77 +824,39 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + unsigned int arg; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, 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_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique - * and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 5000); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->scan_begin_arg < 5000 /* XXX unknown */) { - cmd->scan_begin_arg = 5000; - err++; - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->scan_end_arg > 2) { - /* XXX chanlist stuff? */ - cmd->scan_end_arg = 2; - err++; - } if (cmd->stop_src == TRIG_COUNT) { /* any count is allowed */ - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + } else { /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -1092,10 +864,9 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - tmp = cmd->scan_begin_arg; - dt282x_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + dt282x_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); if (err) return 4; @@ -1105,17 +876,20 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, } static int dt282x_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int x) + struct comedi_subdevice *s, + unsigned int trig_num) { + struct dt282x_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int size; - if (x != 0) + if (trig_num != cmd->start_src) return -EINVAL; size = cfc_read_array_from_buffer(s, devpriv->dma[0].buf, devpriv->dma_maxsize); if (size == 0) { - printk(KERN_ERR "dt282x: AO underrun\n"); + dev_err(dev->class_dev, "AO underrun\n"); return -EPIPE; } prep_ao_dma(dev, 0, size); @@ -1123,12 +897,12 @@ static int dt282x_ao_inttrig(struct comedi_device *dev, size = cfc_read_array_from_buffer(s, devpriv->dma[1].buf, devpriv->dma_maxsize); if (size == 0) { - printk(KERN_ERR "dt282x: AO underrun\n"); + dev_err(dev->class_dev, "AO underrun\n"); return -EPIPE; } prep_ao_dma(dev, 1, size); - update_supcsr(DT2821_STRIG); + outw(devpriv->supcsr | DT2821_STRIG, dev->iobase + DT2821_SUPCSR); s->async->inttrig = NULL; return 1; @@ -1136,6 +910,7 @@ static int dt282x_ao_inttrig(struct comedi_device *dev, static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct dt282x_private *devpriv = dev->private; int timer; struct comedi_cmd *cmd = &s->async->cmd; @@ -1149,7 +924,8 @@ static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) dt282x_disable_dma(dev); devpriv->supcsr = DT2821_ERRINTEN | DT2821_DS1 | DT2821_DDMA; - update_supcsr(DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT); + outw(devpriv->supcsr | DT2821_CLRDMADNE | DT2821_BUFFB | DT2821_DACINIT, + dev->iobase + DT2821_SUPCSR); devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len; devpriv->nread = devpriv->ntrig; @@ -1161,7 +937,7 @@ static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(timer, dev->iobase + DT2821_TMRCTR); devpriv->dacsr = DT2821_SSEL | DT2821_DACLK | DT2821_IDARDY; - update_dacsr(0); + outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); s->async->inttrig = dt282x_ao_inttrig; @@ -1171,56 +947,60 @@ static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) static int dt282x_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct dt282x_private *devpriv = dev->private; + dt282x_disable_dma(dev); devpriv->dacsr = 0; - update_dacsr(0); + outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); devpriv->supcsr = 0; - update_supcsr(DT2821_DACINIT); + outw(devpriv->supcsr | DT2821_DACINIT, dev->iobase + DT2821_SUPCSR); return 0; } static int dt282x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + DT2821_DIODAT); - } + data[1] = inw(dev->iobase + DT2821_DIODAT); - return 2; + return insn->n; } static int dt282x_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int mask; + struct dt282x_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; - mask = (CR_CHAN(insn->chanspec) < 8) ? 0x00ff : 0xff00; - if (data[0]) - s->io_bits |= mask; + if (chan < 8) + mask = 0x00ff; else - s->io_bits &= ~mask; + mask = 0xff00; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + devpriv->dacsr &= ~(DT2821_LBOE | DT2821_HBOE); if (s->io_bits & 0x00ff) devpriv->dacsr |= DT2821_LBOE; - else - devpriv->dacsr &= ~DT2821_LBOE; if (s->io_bits & 0xff00) devpriv->dacsr |= DT2821_HBOE; - else - devpriv->dacsr &= ~DT2821_HBOE; outw(devpriv->dacsr, dev->iobase + DT2821_DACSR); - return 1; + return insn->n; } static const struct comedi_lrange *const ai_range_table[] = { @@ -1270,6 +1050,47 @@ enum { /* i/o base, irq, dma channels */ opt_ai_range, opt_ao0_range, opt_ao1_range, /* range */ }; +static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) +{ + struct dt282x_private *devpriv = dev->private; + int ret; + + devpriv->usedma = 0; + + if (!dma1 && !dma2) + return 0; + + if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7) + return -EINVAL; + + if (dma2 < dma1) { + int i; + i = dma1; + dma1 = dma2; + dma2 = i; + } + + ret = request_dma(dma1, "dt282x A"); + if (ret) + return -EBUSY; + devpriv->dma[0].chan = dma1; + + ret = request_dma(dma2, "dt282x B"); + if (ret) + return -EBUSY; + devpriv->dma[1].chan = dma2; + + devpriv->dma_maxsize = PAGE_SIZE; + devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); + devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); + if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) + return -ENOMEM; + + devpriv->usedma = 1; + + return 0; +} + /* options: 0 i/o base @@ -1286,34 +1107,18 @@ enum { /* i/o base, irq, dma channels */ */ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int i, irq; - int ret; + const struct dt282x_board *board = comedi_board(dev); + struct dt282x_private *devpriv; struct comedi_subdevice *s; - unsigned long iobase; - - dev->board_name = this_board->name; - - iobase = it->options[opt_iobase]; - if (!iobase) - iobase = 0x240; + int ret; + int i; - printk(KERN_INFO "comedi%d: dt282x: 0x%04lx", dev->minor, iobase); - if (!request_region(iobase, DT2821_SIZE, "dt282x")) { - printk(KERN_INFO " I/O port conflict\n"); - return -EBUSY; - } - dev->iobase = iobase; + ret = comedi_request_region(dev, it->options[0], DT2821_SIZE); + if (ret) + return ret; outw(DT2821_BDINIT, dev->iobase + DT2821_SUPCSR); i = inw(dev->iobase + DT2821_ADCSR); -#ifdef DEBUG - printk(KERN_DEBUG " fingerprint=%x,%x,%x,%x,%x", - inw(dev->iobase + DT2821_ADCSR), - inw(dev->iobase + DT2821_CHANCSR), - inw(dev->iobase + DT2821_DACSR), - inw(dev->iobase + DT2821_SUPCSR), - inw(dev->iobase + DT2821_TMRCTR)); -#endif if (((inw(dev->iobase + DT2821_ADCSR) & DT2821_ADCSR_MASK) != DT2821_ADCSR_VAL) || @@ -1325,96 +1130,65 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) != DT2821_SUPCSR_VAL) || ((inw(dev->iobase + DT2821_TMRCTR) & DT2821_TMRCTR_MASK) != DT2821_TMRCTR_VAL)) { - printk(KERN_ERR " board not found"); + dev_err(dev->class_dev, "board not found\n"); return -EIO; } /* should do board test */ - irq = it->options[opt_irq]; -#if 0 - if (irq < 0) { - unsigned long flags; - int irqs; - - save_flags(flags); - sti(); - irqs = probe_irq_on(); - - /* trigger interrupt */ - - udelay(100); - - irq = probe_irq_off(irqs); - restore_flags(flags); - if (0 /* error */) - printk(KERN_ERR " error probing irq (bad)"); - } -#endif - if (irq > 0) { - printk(KERN_INFO " ( irq = %d )", irq); - ret = request_irq(irq, dt282x_interrupt, 0, "dt282x", dev); - if (ret < 0) { - printk(KERN_ERR " failed to get irq\n"); - return -EIO; - } - dev->irq = irq; - } else if (irq == 0) { - printk(KERN_INFO " (no irq)"); - } else { -#if 0 - printk(KERN_INFO " (probe returned multiple irqs--bad)"); -#else - printk(KERN_INFO " (irq probe not implemented)"); -#endif + if (it->options[opt_irq] > 0) { + ret = request_irq(it->options[opt_irq], dt282x_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[opt_irq]; } - ret = alloc_private(dev, sizeof(struct dt282x_private)); - if (ret < 0) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = dt282x_grab_dma(dev, it->options[opt_dma1], - it->options[opt_dma2]); - if (ret < 0) - return ret; + if (dev->irq) { + ret = dt282x_grab_dma(dev, it->options[opt_dma1], + it->options[opt_dma2]); + if (ret < 0) + return ret; + } - ret = alloc_subdevices(dev, 3); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 3); + if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; - dev->read_subdev = s; /* ai subdevice */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ | + s->subdev_flags = SDF_READABLE | ((it->options[opt_diff]) ? SDF_DIFF : SDF_COMMON); s->n_chan = - (it->options[opt_diff]) ? boardtype.adchan_di : boardtype.adchan_se; + (it->options[opt_diff]) ? board->adchan_di : board->adchan_se; s->insn_read = dt282x_ai_insn_read; - s->do_cmdtest = dt282x_ai_cmdtest; - s->do_cmd = dt282x_ai_cmd; - s->cancel = dt282x_ai_cancel; - s->maxdata = (1 << boardtype.adbits) - 1; - s->len_chanlist = 16; + s->maxdata = (1 << board->adbits) - 1; s->range_table = - opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]); + opt_ai_range_lkup(board->ispgl, it->options[opt_ai_range]); devpriv->ad_2scomp = it->options[opt_ai_twos]; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 16; + s->do_cmdtest = dt282x_ai_cmdtest; + s->do_cmd = dt282x_ai_cmd; + s->cancel = dt282x_ai_cancel; + } - s++; + s = &dev->subdevices[1]; - s->n_chan = boardtype.dachan; + s->n_chan = board->dachan; if (s->n_chan) { /* ao subsystem */ s->type = COMEDI_SUBD_AO; - dev->write_subdev = s; - s->subdev_flags = SDF_WRITABLE | SDF_CMD_WRITE; + s->subdev_flags = SDF_WRITABLE; s->insn_read = dt282x_ao_insn_read; s->insn_write = dt282x_ao_insn_write; - s->do_cmdtest = dt282x_ao_cmdtest; - s->do_cmd = dt282x_ao_cmd; - s->cancel = dt282x_ao_cancel; - s->maxdata = (1 << boardtype.dabits) - 1; - s->len_chanlist = 2; + s->maxdata = (1 << board->dabits) - 1; s->range_table_list = devpriv->darangelist; devpriv->darangelist[0] = opt_ao_range_lkup(it->options[opt_ao0_range]); @@ -1422,11 +1196,19 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) opt_ao_range_lkup(it->options[opt_ao1_range]); devpriv->da0_2scomp = it->options[opt_ao0_twos]; devpriv->da1_2scomp = it->options[opt_ao1_twos]; + if (dev->irq) { + dev->write_subdev = s; + s->subdev_flags |= SDF_CMD_WRITE; + s->len_chanlist = 2; + s->do_cmdtest = dt282x_ao_cmdtest; + s->do_cmd = dt282x_ao_cmd; + s->cancel = dt282x_ao_cancel; + } } else { s->type = COMEDI_SUBD_UNUSED; } - s++; + s = &dev->subdevices[2]; /* dio subsystem */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -1436,17 +1218,13 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 1; s->range_table = &range_digital; - printk(KERN_INFO "\n"); - return 0; } -static void free_resources(struct comedi_device *dev) +static void dt282x_detach(struct comedi_device *dev) { - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, DT2821_SIZE); + struct dt282x_private *devpriv = dev->private; + if (dev->private) { if (devpriv->dma[0].chan) free_dma(devpriv->dma[0].chan); @@ -1457,62 +1235,149 @@ static void free_resources(struct comedi_device *dev) if (devpriv->dma[1].buf) free_page((unsigned long)devpriv->dma[1].buf); } + comedi_legacy_detach(dev); } -static int dt282x_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: dt282x: remove\n", dev->minor); - - free_resources(dev); - - return 0; -} - -static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2) -{ - int ret; - - devpriv->usedma = 0; - - if (!dma1 && !dma2) { - printk(KERN_ERR " (no dma)"); - return 0; - } - - if (dma1 == dma2 || dma1 < 5 || dma2 < 5 || dma1 > 7 || dma2 > 7) - return -EINVAL; - - if (dma2 < dma1) { - int i; - i = dma1; - dma1 = dma2; - dma2 = i; - } - - ret = request_dma(dma1, "dt282x A"); - if (ret) - return -EBUSY; - devpriv->dma[0].chan = dma1; - - ret = request_dma(dma2, "dt282x B"); - if (ret) - return -EBUSY; - devpriv->dma[1].chan = dma2; - - devpriv->dma_maxsize = PAGE_SIZE; - devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA); - if (!devpriv->dma[0].buf || !devpriv->dma[1].buf) { - printk(KERN_ERR " can't get DMA memory"); - return -ENOMEM; - } - - printk(KERN_INFO " (dma=%d,%d)", dma1, dma2); - - devpriv->usedma = 1; +static const struct dt282x_board boardtypes[] = { + { + .name = "dt2821", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2821-f", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 6500, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2821-g", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 4000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2823", + .adbits = 16, + .adchan_se = 0, + .adchan_di = 4, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 16, + }, { + .name = "dt2824-pgh", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, { + .name = "dt2824-pgl", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 1, + .dachan = 0, + .dabits = 0, + }, { + .name = "dt2825", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 20000, + .ispgl = 1, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2827", + .adbits = 16, + .adchan_se = 0, + .adchan_di = 4, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2828", + .adbits = 12, + .adchan_se = 4, + .adchan_di = 0, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt2829", + .adbits = 16, + .adchan_se = 8, + .adchan_di = 0, + .ai_speed = 33250, + .ispgl = 0, + .dachan = 2, + .dabits = 16, + }, { + .name = "dt21-ez", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 2, + .dabits = 12, + }, { + .name = "dt23-ez", + .adbits = 16, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, { + .name = "dt24-ez", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 0, + .dachan = 0, + .dabits = 0, + }, { + .name = "dt24-ez-pgl", + .adbits = 12, + .adchan_se = 16, + .adchan_di = 8, + .ai_speed = 10000, + .ispgl = 1, + .dachan = 0, + .dabits = 0, + }, +}; - return 0; -} +static struct comedi_driver dt282x_driver = { + .driver_name = "dt282x", + .module = THIS_MODULE, + .attach = dt282x_attach, + .detach = dt282x_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct dt282x_board), +}; +module_comedi_driver(dt282x_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 6170f7bac46..4ab4de00592 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: dt3000 @@ -29,11 +24,7 @@ Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003, Updated: Mon, 14 Apr 2008 15:41:24 +0100 Status: works -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration Options: not applicable, uses PCI auto config There is code to support AI commands, but it may not work. @@ -57,36 +48,45 @@ AO commands are not supported. you the docs without one, also. */ -#define DEBUG 1 - +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> #include <linux/interrupt.h> + #include "../comedidev.h" -#include <linux/delay.h> -#include "comedi_pci.h" +#include "comedi_fc.h" -#define PCI_VENDOR_ID_DT 0x1116 +static const struct comedi_lrange range_dt3000_ai = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } +}; -static const struct comedi_lrange range_dt3000_ai = { 4, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1.25, 1.25) - } +static const struct comedi_lrange range_dt3000_ai_pgl = { + 4, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02) + } }; -static const struct comedi_lrange range_dt3000_ai_pgl = { 4, { - RANGE(-10, 10), - RANGE(-1, 1), - RANGE(-0.1, 0.1), - RANGE(-0.02, 0.02) - } +enum dt3k_boardid { + BOARD_DT3001, + BOARD_DT3001_PGL, + BOARD_DT3002, + BOARD_DT3003, + BOARD_DT3003_PGL, + BOARD_DT3004, + BOARD_DT3005, }; struct dt3k_boardtype { - const char *name; - unsigned int device_id; int adchan; int adbits; int ai_speed; @@ -96,89 +96,69 @@ struct dt3k_boardtype { }; static const struct dt3k_boardtype dt3k_boardtypes[] = { - {.name = "dt3001", - .device_id = 0x22, - .adchan = 16, - .adbits = 12, - .adrange = &range_dt3000_ai, - .ai_speed = 3000, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt3001-pgl", - .device_id = 0x27, - .adchan = 16, - .adbits = 12, - .adrange = &range_dt3000_ai_pgl, - .ai_speed = 3000, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt3002", - .device_id = 0x23, - .adchan = 32, - .adbits = 12, - .adrange = &range_dt3000_ai, - .ai_speed = 3000, - .dachan = 0, - .dabits = 0, - }, - {.name = "dt3003", - .device_id = 0x24, - .adchan = 64, - .adbits = 12, - .adrange = &range_dt3000_ai, - .ai_speed = 3000, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt3003-pgl", - .device_id = 0x28, - .adchan = 64, - .adbits = 12, - .adrange = &range_dt3000_ai_pgl, - .ai_speed = 3000, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt3004", - .device_id = 0x25, - .adchan = 16, - .adbits = 16, - .adrange = &range_dt3000_ai, - .ai_speed = 10000, - .dachan = 2, - .dabits = 12, - }, - {.name = "dt3005", /* a.k.a. 3004-200 */ - .device_id = 0x26, - .adchan = 16, - .adbits = 16, - .adrange = &range_dt3000_ai, - .ai_speed = 5000, - .dachan = 2, - .dabits = 12, - }, -}; - -#define n_dt3k_boards sizeof(dt3k_boardtypes)/sizeof(struct dt3k_boardtype) -#define this_board ((const struct dt3k_boardtype *)dev->board_ptr) - -static DEFINE_PCI_DEVICE_TABLE(dt3k_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0022) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0027) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0023) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0024) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0028) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0025) }, - { PCI_DEVICE(PCI_VENDOR_ID_DT, 0x0026) }, - { 0 } + [BOARD_DT3001] = { + .name = "dt3001", + .adchan = 16, + .adbits = 12, + .adrange = &range_dt3000_ai, + .ai_speed = 3000, + .dachan = 2, + .dabits = 12, + }, + [BOARD_DT3001_PGL] = { + .name = "dt3001-pgl", + .adchan = 16, + .adbits = 12, + .adrange = &range_dt3000_ai_pgl, + .ai_speed = 3000, + .dachan = 2, + .dabits = 12, + }, + [BOARD_DT3002] = { + .name = "dt3002", + .adchan = 32, + .adbits = 12, + .adrange = &range_dt3000_ai, + .ai_speed = 3000, + }, + [BOARD_DT3003] = { + .name = "dt3003", + .adchan = 64, + .adbits = 12, + .adrange = &range_dt3000_ai, + .ai_speed = 3000, + .dachan = 2, + .dabits = 12, + }, + [BOARD_DT3003_PGL] = { + .name = "dt3003-pgl", + .adchan = 64, + .adbits = 12, + .adrange = &range_dt3000_ai_pgl, + .ai_speed = 3000, + .dachan = 2, + .dabits = 12, + }, + [BOARD_DT3004] = { + .name = "dt3004", + .adchan = 16, + .adbits = 16, + .adrange = &range_dt3000_ai, + .ai_speed = 10000, + .dachan = 2, + .dabits = 12, + }, + [BOARD_DT3005] = { + .name = "dt3005", /* a.k.a. 3004-200 */ + .adchan = 16, + .adbits = 16, + .adrange = &range_dt3000_ai, + .ai_speed = 5000, + .dachan = 2, + .dabits = 12, + }, }; -MODULE_DEVICE_TABLE(pci, dt3k_pci_table); - -#define DT3000_SIZE (4*0x1000) - /* dual-ported RAM location definitions */ #define DPR_DAC_buffer (4*0x000) @@ -264,80 +244,18 @@ MODULE_DEVICE_TABLE(pci, dt3k_pci_table); #define DT3000_CHANNEL_MODE_DI 1 struct dt3k_private { - - struct pci_dev *pci_dev; - resource_size_t phys_addr; - void *io_addr; + void __iomem *io_addr; unsigned int lock; unsigned int ao_readback[2]; unsigned int ai_front; unsigned int ai_rear; }; -#define devpriv ((struct dt3k_private *)dev->private) - -static int dt3000_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dt3000_detach(struct comedi_device *dev); -static struct comedi_driver driver_dt3000 = { - .driver_name = "dt3000", - .module = THIS_MODULE, - .attach = dt3000_attach, - .detach = dt3000_detach, -}; - -static int __devinit driver_dt3000_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_dt3000.driver_name); -} - -static void __devexit driver_dt3000_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_dt3000_pci_driver = { - .id_table = dt3k_pci_table, - .probe = &driver_dt3000_pci_probe, - .remove = __devexit_p(&driver_dt3000_pci_remove) -}; - -static int __init driver_dt3000_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_dt3000); - if (retval < 0) - return retval; - - driver_dt3000_pci_driver.name = (char *)driver_dt3000.driver_name; - return pci_register_driver(&driver_dt3000_pci_driver); -} - -static void __exit driver_dt3000_cleanup_module(void) -{ - pci_unregister_driver(&driver_dt3000_pci_driver); - comedi_driver_unregister(&driver_dt3000); -} - -module_init(driver_dt3000_init_module); -module_exit(driver_dt3000_cleanup_module); - -static void dt3k_ai_empty_fifo(struct comedi_device *dev, - struct comedi_subdevice *s); -static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *arg, - unsigned int round_mode); -static int dt3k_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -#ifdef DEBUG -static void debug_intr_flags(unsigned int flags); -#endif - #define TIMEOUT 100 -static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) +static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) { + struct dt3k_private *devpriv = dev->private; int i; unsigned int status = 0; @@ -349,18 +267,18 @@ static int dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) break; udelay(1); } - if ((status & DT3000_COMPLETION_MASK) == DT3000_NOERROR) - return 0; - - printk("dt3k_send_cmd() timeout/error status=0x%04x\n", status); - return -ETIME; + if ((status & DT3000_COMPLETION_MASK) != DT3000_NOERROR) + dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n", + __func__, status); } static unsigned int dt3k_readsingle(struct comedi_device *dev, unsigned int subsys, unsigned int chan, unsigned int gain) { + struct dt3k_private *devpriv = dev->private; + writew(subsys, devpriv->io_addr + DPR_SubSys); writew(chan, devpriv->io_addr + DPR_Params(0)); @@ -374,6 +292,8 @@ static unsigned int dt3k_readsingle(struct comedi_device *dev, static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, unsigned int chan, unsigned int data) { + struct dt3k_private *devpriv = dev->private; + writew(subsys, devpriv->io_addr + DPR_SubSys); writew(chan, devpriv->io_addr + DPR_Params(0)); @@ -383,82 +303,26 @@ static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, dt3k_send_cmd(dev, CMD_WRITESINGLE); } -static int debug_n_ints = 0; - -/* FIXME! Assumes shared interrupt is for this card. */ -/* What's this debug_n_ints stuff? Obviously needs some work... */ -static irqreturn_t dt3k_interrupt(int irq, void *d) -{ - struct comedi_device *dev = d; - struct comedi_subdevice *s; - unsigned int status; - - if (!dev->attached) - return IRQ_NONE; - - s = dev->subdevices + 0; - status = readw(devpriv->io_addr + DPR_Intr_Flag); -#ifdef DEBUG - debug_intr_flags(status); -#endif - - if (status & DT3000_ADFULL) { - dt3k_ai_empty_fifo(dev, s); - s->async->events |= COMEDI_CB_BLOCK; - } - - if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) - s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - - debug_n_ints++; - if (debug_n_ints >= 10) { - dt3k_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - - comedi_event(dev, s); - return IRQ_HANDLED; -} - -#ifdef DEBUG -static char *intr_flags[] = { - "AdFull", "AdSwError", "AdHwError", "DaEmpty", - "DaSwError", "DaHwError", "CtDone", "CmDone", -}; - -static void debug_intr_flags(unsigned int flags) -{ - int i; - printk("dt3k: intr_flags:"); - for (i = 0; i < 8; i++) { - if (flags & (1 << i)) - printk(" %s", intr_flags[i]); - } - printk("\n"); -} -#endif - static void dt3k_ai_empty_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { + struct dt3k_private *devpriv = dev->private; int front; int rear; int count; int i; - short data; + unsigned short data; front = readw(devpriv->io_addr + DPR_AD_Buf_Front); count = front - devpriv->ai_front; if (count < 0) count += AI_FIFO_DEPTH; - printk("reading %d samples\n", count); - rear = devpriv->ai_rear; for (i = 0; i < count; i++) { data = readw(devpriv->io_addr + DPR_ADC_buffer + rear); - comedi_buf_put(s->async, data); + comedi_buf_put(s, data); rear++; if (rear >= AI_FIFO_DEPTH) rear = 0; @@ -468,131 +332,48 @@ static void dt3k_ai_empty_fifo(struct comedi_device *dev, writew(rear, devpriv->io_addr + DPR_AD_Buf_Rear); } -static int dt3k_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + struct dt3k_private *devpriv = dev->private; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + writew(SUBS_AI, devpriv->io_addr + DPR_SubSys); + dt3k_send_cmd(dev, CMD_STOP); - if (err) - return 1; + writew(0, devpriv->io_addr + DPR_Int_Mask); - /* step 2: make sure trigger sources are unique and mutually compatible */ + return 0; +} - if (err) - return 2; +static int debug_n_ints; - /* step 3: make sure arguments are trivially compatible */ +/* FIXME! Assumes shared interrupt is for this card. */ +/* What's this debug_n_ints stuff? Obviously needs some work... */ +static irqreturn_t dt3k_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct dt3k_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int status; - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + if (!dev->attached) + return IRQ_NONE; - if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < this_board->ai_speed) { - cmd->scan_begin_arg = this_board->ai_speed; - err++; - } - if (cmd->scan_begin_arg > 100 * 16 * 65535) { - cmd->scan_begin_arg = 100 * 16 * 65535; - err++; - } - } else { - /* not supported */ - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < this_board->ai_speed) { - cmd->convert_arg = this_board->ai_speed; - err++; - } - if (cmd->convert_arg > 50 * 16 * 65535) { - cmd->convert_arg = 50 * 16 * 65535; - err++; - } - } else { - /* not supported */ - } + status = readw(devpriv->io_addr + DPR_Intr_Flag); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg > 0x00ffffff) { - cmd->stop_arg = 0x00ffffff; - err++; - } - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + if (status & DT3000_ADFULL) { + dt3k_ai_empty_fifo(dev, s); + s->async->events |= COMEDI_CB_BLOCK; } - if (err) - return 3; - - /* step 4: fix up any arguments */ - - if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - dt3k_ns_to_timer(100, &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; - } else { - /* not supported */ - } - if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - dt3k_ns_to_timer(50, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; - } - } else { - /* not supported */ - } + if (status & (DT3000_ADSWERR | DT3000_ADHWERR)) + s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - if (err) - return 4; + debug_n_ints++; + if (debug_n_ints >= 10) + s->async->events |= COMEDI_CB_EOA; - return 0; + cfc_handle_events(dev, s); + return IRQ_HANDLED; } static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec, @@ -630,17 +411,94 @@ static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec, return (prescale << 16) | (divider); } +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); + 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); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT); + + 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); + + if (cmd->scan_begin_src == TRIG_TIMER) { + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + this_board->ai_speed); + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, + 100 * 16 * 65535); + } + + if (cmd->convert_src == TRIG_TIMER) { + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + this_board->ai_speed); + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, + 50 * 16 * 65535); + } + + 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; + dt3k_ns_to_timer(100, &arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); + } + + if (cmd->convert_src == TRIG_TIMER) { + arg = cmd->convert_arg; + dt3k_ns_to_timer(50, &arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); + } + } + + if (err) + return 4; + + return 0; +} + static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct dt3k_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int i; unsigned int chan, range, aref; unsigned int divider; unsigned int tscandiv; - int ret; unsigned int mode; - printk("dt3k_ai_cmd:\n"); for (i = 0; i < cmd->chanlist_len; i++) { chan = CR_CHAN(cmd->chanlist[i]); range = CR_RANGE(cmd->chanlist[i]); @@ -651,41 +509,29 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) aref = CR_AREF(cmd->chanlist[0]); writew(cmd->scan_end_arg, devpriv->io_addr + DPR_Params(0)); - printk("param[0]=0x%04x\n", cmd->scan_end_arg); if (cmd->convert_src == TRIG_TIMER) { divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); writew((divider >> 16), devpriv->io_addr + DPR_Params(1)); - printk("param[1]=0x%04x\n", divider >> 16); writew((divider & 0xffff), devpriv->io_addr + DPR_Params(2)); - printk("param[2]=0x%04x\n", divider & 0xffff); - } else { - /* not supported */ } if (cmd->scan_begin_src == TRIG_TIMER) { tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); writew((tscandiv >> 16), devpriv->io_addr + DPR_Params(3)); - printk("param[3]=0x%04x\n", tscandiv >> 16); writew((tscandiv & 0xffff), devpriv->io_addr + DPR_Params(4)); - printk("param[4]=0x%04x\n", tscandiv & 0xffff); - } else { - /* not supported */ } mode = DT3000_AD_RETRIG_INTERNAL | 0 | 0; writew(mode, devpriv->io_addr + DPR_Params(5)); - printk("param[5]=0x%04x\n", mode); writew(aref == AREF_DIFF, devpriv->io_addr + DPR_Params(6)); - printk("param[6]=0x%04x\n", aref == AREF_DIFF); writew(AI_FIFO_DEPTH / 2, devpriv->io_addr + DPR_Params(7)); - printk("param[7]=0x%04x\n", AI_FIFO_DEPTH / 2); writew(SUBS_AI, devpriv->io_addr + DPR_SubSys); - ret = dt3k_send_cmd(dev, CMD_CONFIG); + dt3k_send_cmd(dev, CMD_CONFIG); writew(DT3000_ADFULL | DT3000_ADSWERR | DT3000_ADHWERR, devpriv->io_addr + DPR_Int_Mask); @@ -693,19 +539,7 @@ static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) debug_n_ints = 0; writew(SUBS_AI, devpriv->io_addr + DPR_SubSys); - ret = dt3k_send_cmd(dev, CMD_START); - - return 0; -} - -static int dt3k_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - int ret; - - writew(SUBS_AI, devpriv->io_addr + DPR_SubSys); - ret = dt3k_send_cmd(dev, CMD_STOP); - - writew(0, devpriv->io_addr + DPR_Int_Mask); + dt3k_send_cmd(dev, CMD_START); return 0; } @@ -730,6 +564,7 @@ static int dt3k_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, static int dt3k_ao_insn(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; @@ -746,6 +581,7 @@ 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; @@ -758,6 +594,8 @@ static int dt3k_ao_insn_read(struct comedi_device *dev, static void dt3k_dio_config(struct comedi_device *dev, int bits) { + struct dt3k_private *devpriv = dev->private; + /* XXX */ writew(SUBS_DOUT, devpriv->io_addr + DPR_SubSys); @@ -773,57 +611,45 @@ static void dt3k_dio_config(struct comedi_device *dev, int bits) static int dt3k_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int mask; - - mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0; - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } - mask = (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3); - dt3k_dio_config(dev, mask); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 4) + mask = 0x0f; + else + mask = 0xf0; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3)); return insn->n; } static int dt3k_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[1] & data[0]; + if (comedi_dio_update_state(s, data)) dt3k_writesingle(dev, SUBS_DOUT, 0, s->state); - } + data[1] = dt3k_readsingle(dev, SUBS_DIN, 0, 0); - return 2; + return insn->n; } static int dt3k_mem_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct dt3k_private *devpriv = dev->private; unsigned int addr = CR_CHAN(insn->chanspec); int i; @@ -840,92 +666,96 @@ static int dt3k_mem_insn_read(struct comedi_device *dev, return i; } -static int dt_pci_probe(struct comedi_device *dev, int bus, int slot); - -static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int dt3000_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct dt3k_boardtype *this_board = NULL; + struct dt3k_private *devpriv; struct comedi_subdevice *s; - int bus, slot; int ret = 0; - printk("dt3000:"); - bus = it->options[0]; - slot = it->options[1]; + if (context < ARRAY_SIZE(dt3k_boardtypes)) + this_board = &dt3k_boardtypes[context]; + if (!this_board) + return -ENODEV; + dev->board_ptr = this_board; + dev->board_name = this_board->name; - ret = alloc_private(dev, sizeof(struct dt3k_private)); - if (ret < 0) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = dt_pci_probe(dev, bus, slot); + ret = comedi_pci_enable(dev); if (ret < 0) return ret; - if (ret == 0) { - printk(" no DT board found\n"); - return -ENODEV; - } - dev->board_name = this_board->name; + devpriv->io_addr = pci_ioremap_bar(pcidev, 0); + if (!devpriv->io_addr) + return -ENOMEM; - if (request_irq(devpriv->pci_dev->irq, dt3k_interrupt, IRQF_SHARED, - "dt3000", dev)) { - printk(" unable to allocate IRQ %u\n", devpriv->pci_dev->irq); - return -EINVAL; + if (pcidev->irq) { + ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; } - dev->irq = devpriv->pci_dev->irq; - ret = alloc_subdevices(dev, 4); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - s = dev->subdevices; - dev->read_subdev = s; - + s = &dev->subdevices[0]; /* ai subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; - s->n_chan = this_board->adchan; - s->insn_read = dt3k_ai_insn; - s->maxdata = (1 << this_board->adbits) - 1; - s->len_chanlist = 512; - s->range_table = &range_dt3000_ai; /* XXX */ - s->do_cmd = dt3k_ai_cmd; - s->do_cmdtest = dt3k_ai_cmdtest; - s->cancel = dt3k_ai_cancel; - - s++; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = this_board->adchan; + s->insn_read = dt3k_ai_insn; + s->maxdata = (1 << this_board->adbits) - 1; + s->range_table = &range_dt3000_ai; /* XXX */ + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 512; + s->do_cmd = dt3k_ai_cmd; + s->do_cmdtest = dt3k_ai_cmdtest; + s->cancel = dt3k_ai_cancel; + } + + s = &dev->subdevices[1]; /* ao subsystem */ - 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++; + 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 = &dev->subdevices[2]; /* dio subsystem */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->insn_config = dt3k_dio_insn_config; - s->insn_bits = dt3k_dio_insn_bits; - s->maxdata = 1; - s->len_chanlist = 8; - s->range_table = &range_digital; - - s++; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->insn_config = dt3k_dio_insn_config; + s->insn_bits = dt3k_dio_insn_bits; + s->maxdata = 1; + s->len_chanlist = 8; + s->range_table = &range_digital; + + s = &dev->subdevices[3]; /* mem subsystem */ - s->type = COMEDI_SUBD_MEMORY; - s->subdev_flags = SDF_READABLE; - s->n_chan = 0x1000; - s->insn_read = dt3k_mem_insn_read; - s->maxdata = 0xff; - s->len_chanlist = 1; - s->range_table = &range_unknown; + s->type = COMEDI_SUBD_MEMORY; + s->subdev_flags = SDF_READABLE; + s->n_chan = 0x1000; + s->insn_read = dt3k_mem_insn_read; + s->maxdata = 0xff; + s->len_chanlist = 1; + s->range_table = &range_unknown; #if 0 - s++; + s = &dev->subdevices[4]; /* proc subsystem */ s->type = COMEDI_SUBD_PROC; #endif @@ -933,99 +763,51 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static int dt3000_detach(struct comedi_device *dev) +static void dt3000_detach(struct comedi_device *dev) { + struct dt3k_private *devpriv = dev->private; + if (dev->irq) free_irq(dev->irq, dev); - if (devpriv) { - if (devpriv->pci_dev) { - if (devpriv->phys_addr) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } if (devpriv->io_addr) iounmap(devpriv->io_addr); } - /* XXX */ - - return 0; + comedi_pci_disable(dev); } -static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board); -static int setup_pci(struct comedi_device *dev); - -static int dt_pci_probe(struct comedi_device *dev, int bus, int slot) -{ - int board; - int ret; - struct pci_dev *pcidev; - - pcidev = NULL; - while ((pcidev = dt_pci_find_device(pcidev, &board)) != NULL) { - if ((bus == 0 && slot == 0) || - (pcidev->bus->number == bus && - PCI_SLOT(pcidev->devfn) == slot)) { - break; - } - } - devpriv->pci_dev = pcidev; - - if (board >= 0) - dev->board_ptr = dt3k_boardtypes + board; - - if (!devpriv->pci_dev) - return 0; - - ret = setup_pci(dev); - if (ret < 0) - return ret; - - return 1; -} +static struct comedi_driver dt3000_driver = { + .driver_name = "dt3000", + .module = THIS_MODULE, + .auto_attach = dt3000_auto_attach, + .detach = dt3000_detach, +}; -static int setup_pci(struct comedi_device *dev) +static int dt3000_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - resource_size_t addr; - int ret; - - ret = comedi_pci_enable(devpriv->pci_dev, "dt3000"); - if (ret < 0) - return ret; - - addr = pci_resource_start(devpriv->pci_dev, 0); - devpriv->phys_addr = addr; - devpriv->io_addr = ioremap(devpriv->phys_addr, DT3000_SIZE); - if (!devpriv->io_addr) - return -ENOMEM; -#if DEBUG - printk("0x%08llx mapped to %p, ", - (unsigned long long)devpriv->phys_addr, devpriv->io_addr); -#endif - - return 0; + return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data); } -static struct pci_dev *dt_pci_find_device(struct pci_dev *from, int *board) -{ - int i; +static const struct pci_device_id dt3000_pci_table[] = { + { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 }, + { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 }, + { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 }, + { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 }, + { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 }, + { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL }, + { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, dt3000_pci_table); - for (from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from); - from != NULL; - from = pci_get_device(PCI_VENDOR_ID_DT, PCI_ANY_ID, from)) { - for (i = 0; i < n_dt3k_boards; i++) { - if (from->device == dt3k_boardtypes[i].device_id) { - *board = i; - return from; - } - } - printk - ("unknown Data Translation PCI device found with device_id=0x%04x\n", - from->device); - } - *board = -1; - return from; -} +static struct pci_driver dt3000_pci_driver = { + .name = "dt3000", + .id_table = dt3000_pci_table, + .probe = dt3000_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 32d9c42e965..b3aeb6fb2ad 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -15,11 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ /* @@ -44,11 +39,8 @@ for my needs. */ #include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/slab.h> #include <linux/module.h> -#include <linux/kref.h> +#include <linux/errno.h> #include <linux/uaccess.h> #include <linux/usb.h> @@ -58,6 +50,9 @@ for my needs. #define DT9812_MAX_WRITE_CMD_PIPE_SIZE 32 #define DT9812_MAX_READ_CMD_PIPE_SIZE 32 +/* usb_bulk_msg() timout in milliseconds */ +#define DT9812_USB_TIMEOUT 1000 + /* * See Silican Laboratories C8051F020/1/2/3 manual */ @@ -89,13 +84,9 @@ for my needs. #define F020_MASK_DACxCN_DACxEN 0x80 enum { - /* A/D D/A DI DO CT */ - DT9812_DEVID_DT9812_10, /* 8 2 8 8 1 +/- 10V */ - DT9812_DEVID_DT9812_2PT5, /* 8 2 8 8 1 0-2.44V */ -#if 0 - DT9812_DEVID_DT9813, /* 16 2 4 4 1 +/- 10V */ - DT9812_DEVID_DT9814 /* 24 2 0 0 1 +/- 10V */ -#endif + /* A/D D/A DI DO CT */ + DT9812_DEVID_DT9812_10, /* 8 2 8 8 1 +/- 10V */ + DT9812_DEVID_DT9812_2PT5, /* 8 2 8 8 1 0-2.44V */ }; enum dt9812_gain { @@ -191,12 +182,12 @@ enum { }; struct dt9812_flash_data { - u16 numbytes; - u16 address; + __le16 numbytes; + __le16 address; }; #define DT9812_MAX_NUM_MULTI_BYTE_RDS \ - ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8)) + ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8)) struct dt9812_read_multi { u8 count; @@ -209,8 +200,8 @@ struct dt9812_write_byte { }; #define DT9812_MAX_NUM_MULTI_BYTE_WRTS \ - ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \ - sizeof(struct dt9812_write_byte)) + ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \ + sizeof(struct dt9812_write_byte)) struct dt9812_write_multi { u8 count; @@ -224,7 +215,8 @@ struct dt9812_rmw_byte { }; #define DT9812_MAX_NUM_MULTI_BYTE_RMWS \ - ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(struct dt9812_rmw_byte)) + ((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \ + sizeof(struct dt9812_rmw_byte)) struct dt9812_rmw_multi { u8 count; @@ -232,117 +224,32 @@ struct dt9812_rmw_multi { }; struct dt9812_usb_cmd { - u32 cmd; + __le32 cmd; union { struct dt9812_flash_data flash_data_info; struct dt9812_read_multi read_multi_info; struct dt9812_write_multi write_multi_info; struct dt9812_rmw_multi rmw_multi_info; } u; -#if 0 - WRITE_BYTE_INFO WriteByteInfo; - READ_BYTE_INFO ReadByteInfo; - WRITE_MULTI_INFO WriteMultiInfo; - READ_MULTI_INFO ReadMultiInfo; - RMW_BYTE_INFO RMWByteInfo; - RMW_MULTI_INFO RMWMultiInfo; - DAC_THRESHOLD_INFO DacThresholdInfo; - INT_ON_CHANGE_MASK_INFO IntOnChangeMaskInfo; - CGL_INFO CglInfo; - SUBSYSTEM_INFO SubsystemInfo; - CAL_POT_CMD CalPotCmd; - WRITE_DEV_BYTE_INFO WriteDevByteInfo; - READ_DEV_BYTE_INFO ReadDevByteInfo; - WRITE_DEV_MULTI_INFO WriteDevMultiInfo; - READ_DEV_MULTI_INFO ReadDevMultiInfo; - READ_SINGLE_VALUE_INFO ReadSingleValueInfo; - WRITE_SINGLE_VALUE_INFO WriteSingleValueInfo; -#endif -}; - -#define DT9812_NUM_SLOTS 16 - -static DEFINE_SEMAPHORE(dt9812_mutex); - -static const struct usb_device_id dt9812_table[] = { - {USB_DEVICE(0x0867, 0x9812)}, - {} /* Terminating entry */ }; -MODULE_DEVICE_TABLE(usb, dt9812_table); - -struct usb_dt9812 { - struct slot_dt9812 *slot; - struct usb_device *udev; - struct usb_interface *interface; - u16 vendor; - u16 product; - u16 device; - u32 serial; +struct dt9812_private { + struct semaphore sem; struct { __u8 addr; size_t size; - } message_pipe, command_write, command_read, write_stream, read_stream; - struct kref kref; - u16 analog_out_shadow[2]; - u8 digital_out_shadow; -}; - -struct comedi_dt9812 { - struct slot_dt9812 *slot; - u32 serial; -}; - -struct slot_dt9812 { - struct semaphore mutex; - u32 serial; - struct usb_dt9812 *usb; - struct comedi_dt9812 *comedi; -}; - -static const struct comedi_lrange dt9812_10_ain_range = { 1, { - BIP_RANGE(10), - } -}; - -static const struct comedi_lrange dt9812_2pt5_ain_range = { 1, { - UNI_RANGE(2.5), - } -}; - -static const struct comedi_lrange dt9812_10_aout_range = { 1, { - BIP_RANGE(10), - } -}; - -static const struct comedi_lrange dt9812_2pt5_aout_range = { 1, { - UNI_RANGE(2.5), - } + } cmd_wr, cmd_rd; + u16 device; + u16 ao_shadow[2]; }; -static struct slot_dt9812 dt9812[DT9812_NUM_SLOTS]; - -/* Useful shorthand access to private data */ -#define devpriv ((struct comedi_dt9812 *)dev->private) - -static inline struct usb_dt9812 *to_dt9812_dev(struct kref *d) -{ - return container_of(d, struct usb_dt9812, kref); -} - -static void dt9812_delete(struct kref *kref) -{ - struct usb_dt9812 *dev = to_dt9812_dev(kref); - - usb_put_dev(dev->udev); - kfree(dev); -} - -static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf, - size_t buf_size) +static int dt9812_read_info(struct comedi_device *dev, + int offset, void *buf, size_t buf_size) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; - int count, retval; + int count, ret; cmd.cmd = cpu_to_le32(DT9812_R_FLASH_DATA); cmd.u.flash_data_info.address = @@ -350,25 +257,23 @@ static int dt9812_read_info(struct usb_dt9812 *dev, int offset, void *buf, cmd.u.flash_data_info.numbytes = cpu_to_le16(buf_size); /* DT9812 only responds to 32 byte writes!! */ - count = 32; - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, - dev->command_write.addr), - &cmd, 32, &count, HZ * 1); - if (retval) - return retval; - retval = usb_bulk_msg(dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->command_read.addr), - buf, buf_size, &count, HZ * 1); - return retval; + ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), + &cmd, 32, &count, DT9812_USB_TIMEOUT); + if (ret) + return ret; + + return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr), + buf, buf_size, &count, DT9812_USB_TIMEOUT); } -static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, - u8 * address, u8 * value) +static int dt9812_read_multiple_registers(struct comedi_device *dev, + int reg_count, u8 *address, + u8 *value) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; - int i, count, retval; + int i, count, ret; cmd.cmd = cpu_to_le32(DT9812_R_MULTI_BYTE_REG); cmd.u.read_multi_info.count = reg_count; @@ -376,26 +281,23 @@ static int dt9812_read_multiple_registers(struct usb_dt9812 *dev, int reg_count, cmd.u.read_multi_info.address[i] = address[i]; /* DT9812 only responds to 32 byte writes!! */ - count = 32; - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, - dev->command_write.addr), - &cmd, 32, &count, HZ * 1); - if (retval) - return retval; - retval = usb_bulk_msg(dev->udev, - usb_rcvbulkpipe(dev->udev, - dev->command_read.addr), - value, reg_count, &count, HZ * 1); - return retval; + ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), + &cmd, 32, &count, DT9812_USB_TIMEOUT); + if (ret) + return ret; + + return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr), + value, reg_count, &count, DT9812_USB_TIMEOUT); } -static int dt9812_write_multiple_registers(struct usb_dt9812 *dev, - int reg_count, u8 * address, - u8 * value) +static int dt9812_write_multiple_registers(struct comedi_device *dev, + int reg_count, u8 *address, + u8 *value) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; - int i, count, retval; + int i, count; cmd.cmd = cpu_to_le32(DT9812_W_MULTI_BYTE_REG); cmd.u.read_multi_info.count = reg_count; @@ -403,19 +305,20 @@ static int dt9812_write_multiple_registers(struct usb_dt9812 *dev, cmd.u.write_multi_info.write[i].address = address[i]; cmd.u.write_multi_info.write[i].value = value[i]; } + /* DT9812 only responds to 32 byte writes!! */ - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, - dev->command_write.addr), - &cmd, 32, &count, HZ * 1); - return retval; + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), + &cmd, 32, &count, DT9812_USB_TIMEOUT); } -static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count, +static int dt9812_rmw_multiple_registers(struct comedi_device *dev, + int reg_count, struct dt9812_rmw_byte *rmw) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; struct dt9812_usb_cmd cmd; - int i, count, retval; + int i, count; cmd.cmd = cpu_to_le32(DT9812_RMW_MULTI_BYTE_REG); cmd.u.rmw_multi_info.count = reg_count; @@ -423,76 +326,52 @@ static int dt9812_rmw_multiple_registers(struct usb_dt9812 *dev, int reg_count, cmd.u.rmw_multi_info.rmw[i] = rmw[i]; /* DT9812 only responds to 32 byte writes!! */ - retval = usb_bulk_msg(dev->udev, - usb_sndbulkpipe(dev->udev, - dev->command_write.addr), - &cmd, 32, &count, HZ * 1); - return retval; + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr), + &cmd, 32, &count, DT9812_USB_TIMEOUT); } -static int dt9812_digital_in(struct slot_dt9812 *slot, u8 * bits) +static int dt9812_digital_in(struct comedi_device *dev, u8 *bits) { - int result = -ENODEV; - - down(&slot->mutex); - if (slot->usb) { - u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 }; - u8 value[2]; - - result = dt9812_read_multiple_registers(slot->usb, 2, reg, - value); - if (result == 0) { - /* - * bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital - * input port bit 3 in F020_SFR_P1 is bit 7 in the - * digital input port - */ - *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4); - /* printk("%2.2x, %2.2x -> %2.2x\n", - value[0], value[1], *bits); */ - } + struct dt9812_private *devpriv = dev->private; + u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 }; + u8 value[2]; + int ret; + + down(&devpriv->sem); + ret = dt9812_read_multiple_registers(dev, 2, reg, value); + if (ret == 0) { + /* + * bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital + * input port bit 3 in F020_SFR_P1 is bit 7 in the + * digital input port + */ + *bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4); } - up(&slot->mutex); + up(&devpriv->sem); - return result; + return ret; } -static int dt9812_digital_out(struct slot_dt9812 *slot, u8 bits) +static int dt9812_digital_out(struct comedi_device *dev, u8 bits) { - int result = -ENODEV; - - down(&slot->mutex); - if (slot->usb) { - u8 reg[1]; - u8 value[1]; - - reg[0] = F020_SFR_P2; - value[0] = bits; - result = dt9812_write_multiple_registers(slot->usb, 1, reg, - value); - slot->usb->digital_out_shadow = bits; - } - up(&slot->mutex); - return result; -} + struct dt9812_private *devpriv = dev->private; + u8 reg[1] = { F020_SFR_P2 }; + u8 value[1] = { bits }; + int ret; -static int dt9812_digital_out_shadow(struct slot_dt9812 *slot, u8 * bits) -{ - int result = -ENODEV; + down(&devpriv->sem); + ret = dt9812_write_multiple_registers(dev, 1, reg, value); + up(&devpriv->sem); - down(&slot->mutex); - if (slot->usb) { - *bits = slot->usb->digital_out_shadow; - result = 0; - } - up(&slot->mutex); - return result; + return ret; } -static void dt9812_configure_mux(struct usb_dt9812 *dev, +static void dt9812_configure_mux(struct comedi_device *dev, struct dt9812_rmw_byte *rmw, int channel) { - if (dev->device == DT9812_DEVID_DT9812_10) { + struct dt9812_private *devpriv = dev->private; + + if (devpriv->device == DT9812_DEVID_DT9812_10) { /* In the DT9812/10V MUX is selected by P1.5-7 */ rmw->address = F020_SFR_P1; rmw->and_mask = 0xe0; @@ -505,18 +384,21 @@ static void dt9812_configure_mux(struct usb_dt9812 *dev, } } -static void dt9812_configure_gain(struct usb_dt9812 *dev, +static void dt9812_configure_gain(struct comedi_device *dev, struct dt9812_rmw_byte *rmw, enum dt9812_gain gain) { - if (dev->device == DT9812_DEVID_DT9812_10) { - /* In the DT9812/10V, there is an external gain of 0.5 */ + struct dt9812_private *devpriv = dev->private; + + /* In the DT9812/10V, there is an external gain of 0.5 */ + if (devpriv->device == DT9812_DEVID_DT9812_10) gain <<= 1; - } rmw->address = F020_SFR_ADC0CF; rmw->and_mask = F020_MASK_ADC0CF_AMP0GN2 | - F020_MASK_ADC0CF_AMP0GN1 | F020_MASK_ADC0CF_AMP0GN0; + F020_MASK_ADC0CF_AMP0GN1 | + F020_MASK_ADC0CF_AMP0GN0; + switch (gain) { /* * 000 -> Gain = 1 @@ -527,9 +409,11 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev, * 11x -> Gain = 0.5 */ case DT9812_GAIN_0PT5: - rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 || - F020_MASK_ADC0CF_AMP0GN1; + rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 | + F020_MASK_ADC0CF_AMP0GN1; break; + default: + /* this should never happen, just use a gain of 1 */ case DT9812_GAIN_1: rmw->or_value = 0x00; break; @@ -540,21 +424,19 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev, rmw->or_value = F020_MASK_ADC0CF_AMP0GN1; break; case DT9812_GAIN_8: - rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 || - F020_MASK_ADC0CF_AMP0GN0; + rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 | + F020_MASK_ADC0CF_AMP0GN0; break; case DT9812_GAIN_16: rmw->or_value = F020_MASK_ADC0CF_AMP0GN2; break; - default: - err("Illegal gain %d\n", gain); - } } -static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value, - enum dt9812_gain gain) +static int dt9812_analog_in(struct comedi_device *dev, + int channel, u16 *value, enum dt9812_gain gain) { + struct dt9812_private *devpriv = dev->private; struct dt9812_rmw_byte rmw[3]; u8 reg[3] = { F020_SFR_ADC0CN, @@ -562,31 +444,30 @@ static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value, F020_SFR_ADC0L }; u8 val[3]; - int result = -ENODEV; + int ret; - down(&slot->mutex); - if (!slot->usb) - goto exit; + down(&devpriv->sem); /* 1 select the gain */ - dt9812_configure_gain(slot->usb, &rmw[0], gain); + dt9812_configure_gain(dev, &rmw[0], gain); /* 2 set the MUX to select the channel */ - dt9812_configure_mux(slot->usb, &rmw[1], channel); + dt9812_configure_mux(dev, &rmw[1], channel); /* 3 start conversion */ rmw[2].address = F020_SFR_ADC0CN; rmw[2].and_mask = 0xff; rmw[2].or_value = F020_MASK_ADC0CN_AD0EN | F020_MASK_ADC0CN_AD0BUSY; - result = dt9812_rmw_multiple_registers(slot->usb, 3, rmw); - if (result) + ret = dt9812_rmw_multiple_registers(dev, 3, rmw); + if (ret) goto exit; /* read the status and ADC */ - result = dt9812_read_multiple_registers(slot->usb, 3, reg, val); - if (result) + ret = dt9812_read_multiple_registers(dev, 3, reg, val); + if (ret) goto exit; + /* * An ADC conversion takes 16 SAR clocks cycles, i.e. about 9us. * Therefore, between the instant that AD0BUSY was set via @@ -598,7 +479,7 @@ static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value, */ if ((val[0] & (F020_MASK_ADC0CN_AD0INT | F020_MASK_ADC0CN_AD0BUSY)) == F020_MASK_ADC0CN_AD0INT) { - switch (slot->usb->device) { + switch (devpriv->device) { case DT9812_DEVID_DT9812_10: /* * For DT9812-10V the personality module set the @@ -614,555 +495,385 @@ static int dt9812_analog_in(struct slot_dt9812 *slot, int channel, u16 * value, } exit: - up(&slot->mutex); - return result; + up(&devpriv->sem); + + return ret; } -static int dt9812_analog_out_shadow(struct slot_dt9812 *slot, int channel, - u16 * value) +static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value) { - int result = -ENODEV; + struct dt9812_private *devpriv = dev->private; + struct dt9812_rmw_byte rmw[3]; + int ret; + + down(&devpriv->sem); + + switch (channel) { + case 0: + /* 1. Set DAC mode */ + rmw[0].address = F020_SFR_DAC0CN; + rmw[0].and_mask = 0xff; + rmw[0].or_value = F020_MASK_DACxCN_DACxEN; + + /* 2 load low byte of DAC value first */ + rmw[1].address = F020_SFR_DAC0L; + rmw[1].and_mask = 0xff; + rmw[1].or_value = value & 0xff; + + /* 3 load high byte of DAC value next to latch the + 12-bit value */ + rmw[2].address = F020_SFR_DAC0H; + rmw[2].and_mask = 0xff; + rmw[2].or_value = (value >> 8) & 0xf; + break; - down(&slot->mutex); - if (slot->usb) { - *value = slot->usb->analog_out_shadow[channel]; - result = 0; + case 1: + /* 1. Set DAC mode */ + rmw[0].address = F020_SFR_DAC1CN; + rmw[0].and_mask = 0xff; + rmw[0].or_value = F020_MASK_DACxCN_DACxEN; + + /* 2 load low byte of DAC value first */ + rmw[1].address = F020_SFR_DAC1L; + rmw[1].and_mask = 0xff; + rmw[1].or_value = value & 0xff; + + /* 3 load high byte of DAC value next to latch the + 12-bit value */ + rmw[2].address = F020_SFR_DAC1H; + rmw[2].and_mask = 0xff; + rmw[2].or_value = (value >> 8) & 0xf; + break; } - up(&slot->mutex); + ret = dt9812_rmw_multiple_registers(dev, 3, rmw); + devpriv->ao_shadow[channel] = value; - return result; + up(&devpriv->sem); + + return ret; } -static int dt9812_analog_out(struct slot_dt9812 *slot, int channel, u16 value) +static int dt9812_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int result = -ENODEV; + u8 bits = 0; + int ret; - down(&slot->mutex); - if (slot->usb) { - struct dt9812_rmw_byte rmw[3]; + ret = dt9812_digital_in(dev, &bits); + if (ret) + return ret; - switch (channel) { - case 0: - /* 1. Set DAC mode */ - rmw[0].address = F020_SFR_DAC0CN; - rmw[0].and_mask = 0xff; - rmw[0].or_value = F020_MASK_DACxCN_DACxEN; - - /* 2 load low byte of DAC value first */ - rmw[1].address = F020_SFR_DAC0L; - rmw[1].and_mask = 0xff; - rmw[1].or_value = value & 0xff; - - /* 3 load high byte of DAC value next to latch the - 12-bit value */ - rmw[2].address = F020_SFR_DAC0H; - rmw[2].and_mask = 0xff; - rmw[2].or_value = (value >> 8) & 0xf; - break; + data[1] = bits; - case 1: - /* 1. Set DAC mode */ - rmw[0].address = F020_SFR_DAC1CN; - rmw[0].and_mask = 0xff; - rmw[0].or_value = F020_MASK_DACxCN_DACxEN; - - /* 2 load low byte of DAC value first */ - rmw[1].address = F020_SFR_DAC1L; - rmw[1].and_mask = 0xff; - rmw[1].or_value = value & 0xff; - - /* 3 load high byte of DAC value next to latch the - 12-bit value */ - rmw[2].address = F020_SFR_DAC1H; - rmw[2].and_mask = 0xff; - rmw[2].or_value = (value >> 8) & 0xf; - break; - } - result = dt9812_rmw_multiple_registers(slot->usb, 3, rmw); - slot->usb->analog_out_shadow[channel] = value; + return insn->n; +} + +static int dt9812_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) + dt9812_digital_out(dev, s->state); + + data[1] = s->state; + + return insn->n; +} + +static int dt9812_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + u16 val = 0; + int ret; + int i; + + for (i = 0; i < insn->n; i++) { + ret = dt9812_analog_in(dev, chan, &val, DT9812_GAIN_1); + if (ret) + return ret; + data[i] = val; } - up(&slot->mutex); - return result; + return insn->n; } -/* - * USB framework functions - */ +static int dt9812_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dt9812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + down(&devpriv->sem); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_shadow[chan]; + up(&devpriv->sem); + + return insn->n; +} -static int dt9812_probe(struct usb_interface *interface, - const struct usb_device_id *id) +static int dt9812_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int retval = -ENOMEM; - struct usb_dt9812 *dev = NULL; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *endpoint; + unsigned int chan = CR_CHAN(insn->chanspec); + int ret; int i; - u8 fw; - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); - goto error; + for (i = 0; i < insn->n; i++) { + ret = dt9812_analog_out(dev, chan, data[i]); + if (ret) + return ret; } - kref_init(&dev->kref); - dev->udev = usb_get_dev(interface_to_usbdev(interface)); - dev->interface = interface; + return insn->n; +} - /* Check endpoints */ - iface_desc = interface->cur_altsetting; +static int dt9812_find_endpoints(struct comedi_device *dev) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_host_interface *host = intf->cur_altsetting; + struct dt9812_private *devpriv = dev->private; + struct usb_endpoint_descriptor *ep; + int i; - if (iface_desc->desc.bNumEndpoints != 5) { - err("Wrong number of endpints."); - retval = -ENODEV; - goto error; + if (host->desc.bNumEndpoints != 5) { + dev_err(dev->class_dev, "Wrong number of endpoints\n"); + return -ENODEV; } - for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { - int direction = -1; - endpoint = &iface_desc->endpoint[i].desc; + for (i = 0; i < host->desc.bNumEndpoints; ++i) { + int dir = -1; + ep = &host->endpoint[i].desc; switch (i) { case 0: - direction = USB_DIR_IN; - dev->message_pipe.addr = endpoint->bEndpointAddress; - dev->message_pipe.size = - le16_to_cpu(endpoint->wMaxPacketSize); - + /* unused message pipe */ + dir = USB_DIR_IN; break; case 1: - direction = USB_DIR_OUT; - dev->command_write.addr = endpoint->bEndpointAddress; - dev->command_write.size = - le16_to_cpu(endpoint->wMaxPacketSize); + dir = USB_DIR_OUT; + devpriv->cmd_wr.addr = ep->bEndpointAddress; + devpriv->cmd_wr.size = le16_to_cpu(ep->wMaxPacketSize); break; case 2: - direction = USB_DIR_IN; - dev->command_read.addr = endpoint->bEndpointAddress; - dev->command_read.size = - le16_to_cpu(endpoint->wMaxPacketSize); + dir = USB_DIR_IN; + devpriv->cmd_rd.addr = ep->bEndpointAddress; + devpriv->cmd_rd.size = le16_to_cpu(ep->wMaxPacketSize); break; case 3: - direction = USB_DIR_OUT; - dev->write_stream.addr = endpoint->bEndpointAddress; - dev->write_stream.size = - le16_to_cpu(endpoint->wMaxPacketSize); + /* unused write stream */ + dir = USB_DIR_OUT; break; case 4: - direction = USB_DIR_IN; - dev->read_stream.addr = endpoint->bEndpointAddress; - dev->read_stream.size = - le16_to_cpu(endpoint->wMaxPacketSize); + /* unused read stream */ + dir = USB_DIR_IN; break; } - if ((endpoint->bEndpointAddress & USB_DIR_IN) != direction) { - dev_err(&interface->dev, - "Endpoint has wrong direction.\n"); - retval = -ENODEV; - goto error; + if ((ep->bEndpointAddress & USB_DIR_IN) != dir) { + dev_err(dev->class_dev, + "Endpoint has wrong direction\n"); + return -ENODEV; } } - if (dt9812_read_info(dev, 0, &fw, sizeof(fw)) != 0) { + return 0; +} + +static int dt9812_reset_device(struct comedi_device *dev) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct dt9812_private *devpriv = dev->private; + u32 serial; + u16 vendor; + u16 product; + u8 tmp8; + __le16 tmp16; + __le32 tmp32; + int ret; + int i; + + ret = dt9812_read_info(dev, 0, &tmp8, sizeof(tmp8)); + if (ret) { /* * Seems like a configuration reset is necessary if driver is * reloaded while device is attached */ - usb_reset_configuration(dev->udev); + usb_reset_configuration(usb); for (i = 0; i < 10; i++) { - retval = dt9812_read_info(dev, 1, &fw, sizeof(fw)); - if (retval == 0) { - dev_info(&interface->dev, - "usb_reset_configuration succeeded " - "after %d iterations\n", i); + ret = dt9812_read_info(dev, 1, &tmp8, sizeof(tmp8)); + if (ret == 0) break; - } - } - } - - if (dt9812_read_info(dev, 1, &dev->vendor, sizeof(dev->vendor)) != 0) { - err("Failed to read vendor."); - retval = -ENODEV; - goto error; - } - if (dt9812_read_info(dev, 3, &dev->product, sizeof(dev->product)) != 0) { - err("Failed to read product."); - retval = -ENODEV; - goto error; - } - if (dt9812_read_info(dev, 5, &dev->device, sizeof(dev->device)) != 0) { - err("Failed to read device."); - retval = -ENODEV; - goto error; - } - if (dt9812_read_info(dev, 7, &dev->serial, sizeof(dev->serial)) != 0) { - err("Failed to read serial."); - retval = -ENODEV; - goto error; - } - - dev->vendor = le16_to_cpu(dev->vendor); - dev->product = le16_to_cpu(dev->product); - dev->device = le16_to_cpu(dev->device); - dev->serial = le32_to_cpu(dev->serial); - switch (dev->device) { - case DT9812_DEVID_DT9812_10: - dev->analog_out_shadow[0] = 0x0800; - dev->analog_out_shadow[1] = 0x800; - break; - case DT9812_DEVID_DT9812_2PT5: - dev->analog_out_shadow[0] = 0x0000; - dev->analog_out_shadow[1] = 0x0000; - break; - } - dev->digital_out_shadow = 0; - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - /* let the user know what node this device is now attached to */ - dev_info(&interface->dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n", - dev->vendor, dev->product, dev->device, dev->serial); - - down(&dt9812_mutex); - { - /* Find a slot for the USB device */ - struct slot_dt9812 *first = NULL; - struct slot_dt9812 *best = NULL; - - for (i = 0; i < DT9812_NUM_SLOTS; i++) { - if (!first && !dt9812[i].usb && dt9812[i].serial == 0) - first = &dt9812[i]; - if (!best && dt9812[i].serial == dev->serial) - best = &dt9812[i]; } - - if (!best) - best = first; - - if (best) { - down(&best->mutex); - best->usb = dev; - dev->slot = best; - up(&best->mutex); + if (ret) { + dev_err(dev->class_dev, + "unable to reset configuration\n"); + return ret; } } - up(&dt9812_mutex); - return 0; - -error: - if (dev) - kref_put(&dev->kref, dt9812_delete); - return retval; -} - -static void dt9812_disconnect(struct usb_interface *interface) -{ - struct usb_dt9812 *dev; - int minor = interface->minor; - - down(&dt9812_mutex); - dev = usb_get_intfdata(interface); - if (dev->slot) { - down(&dev->slot->mutex); - dev->slot->usb = NULL; - up(&dev->slot->mutex); - dev->slot = NULL; + ret = dt9812_read_info(dev, 1, &tmp16, sizeof(tmp16)); + if (ret) { + dev_err(dev->class_dev, "failed to read vendor id\n"); + return ret; } - usb_set_intfdata(interface, NULL); - up(&dt9812_mutex); - - /* queue final destruction */ - kref_put(&dev->kref, dt9812_delete); + vendor = le16_to_cpu(tmp16); - dev_info(&interface->dev, "USB Dt9812 #%d now disconnected\n", minor); -} - -static struct usb_driver dt9812_usb_driver = { - .name = "dt9812", - .probe = dt9812_probe, - .disconnect = dt9812_disconnect, - .id_table = dt9812_table, -}; - -/* - * Comedi functions - */ - -static int dt9812_comedi_open(struct comedi_device *dev) -{ - int result = -ENODEV; - - down(&devpriv->slot->mutex); - if (devpriv->slot->usb) { - /* We have an attached device, fill in current range info */ - struct comedi_subdevice *s; - - s = &dev->subdevices[0]; - s->n_chan = 8; - s->maxdata = 1; - - s = &dev->subdevices[1]; - s->n_chan = 8; - s->maxdata = 1; - - s = &dev->subdevices[2]; - s->n_chan = 8; - switch (devpriv->slot->usb->device) { - case 0:{ - s->maxdata = 4095; - s->range_table = &dt9812_10_ain_range; - } - break; - case 1:{ - s->maxdata = 4095; - s->range_table = &dt9812_2pt5_ain_range; - } - break; - } - - s = &dev->subdevices[3]; - s->n_chan = 2; - switch (devpriv->slot->usb->device) { - case 0:{ - s->maxdata = 4095; - s->range_table = &dt9812_10_aout_range; - } - break; - case 1:{ - s->maxdata = 4095; - s->range_table = &dt9812_2pt5_aout_range; - } - break; - } - result = 0; + ret = dt9812_read_info(dev, 3, &tmp16, sizeof(tmp16)); + if (ret) { + dev_err(dev->class_dev, "failed to read product id\n"); + return ret; } - up(&devpriv->slot->mutex); - return result; -} + product = le16_to_cpu(tmp16); -static int dt9812_di_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int n; - u8 bits = 0; - - dt9812_digital_in(devpriv->slot, &bits); - for (n = 0; n < insn->n; n++) - data[n] = ((1 << insn->chanspec) & bits) != 0; - return n; -} - -static int dt9812_do_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int n; - u8 bits = 0; - - dt9812_digital_out_shadow(devpriv->slot, &bits); - for (n = 0; n < insn->n; n++) { - u8 mask = 1 << insn->chanspec; - - bits &= ~mask; - if (data[n]) - bits |= mask; + ret = dt9812_read_info(dev, 5, &tmp16, sizeof(tmp16)); + if (ret) { + dev_err(dev->class_dev, "failed to read device id\n"); + return ret; } - dt9812_digital_out(devpriv->slot, bits); - return n; -} - -static int dt9812_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int n; + devpriv->device = le16_to_cpu(tmp16); - for (n = 0; n < insn->n; n++) { - u16 value = 0; - - dt9812_analog_in(devpriv->slot, insn->chanspec, &value, - DT9812_GAIN_1); - data[n] = value; + ret = dt9812_read_info(dev, 7, &tmp32, sizeof(tmp32)); + if (ret) { + dev_err(dev->class_dev, "failed to read serial number\n"); + return ret; } - return n; -} + serial = le32_to_cpu(tmp32); -static int dt9812_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int n; - u16 value; + /* let the user know what node this device is now attached to */ + dev_info(dev->class_dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n", + vendor, product, devpriv->device, serial); - for (n = 0; n < insn->n; n++) { - value = 0; - dt9812_analog_out_shadow(devpriv->slot, insn->chanspec, &value); - data[n] = value; + if (devpriv->device != DT9812_DEVID_DT9812_10 && + devpriv->device != DT9812_DEVID_DT9812_2PT5) { + dev_err(dev->class_dev, "Unsupported device!\n"); + return -EINVAL; } - return n; -} -static int dt9812_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int n; - - for (n = 0; n < insn->n; n++) - dt9812_analog_out(devpriv->slot, insn->chanspec, data[n]); - return n; + return 0; } -static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int dt9812_auto_attach(struct comedi_device *dev, + unsigned long context) { - int i; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct dt9812_private *devpriv; struct comedi_subdevice *s; + bool is_unipolar; + int ret; - dev->board_name = "dt9812"; - - if (alloc_private(dev, sizeof(struct comedi_dt9812)) < 0) - return -ENOMEM; - - /* - * Special open routine, since USB unit may be unattached at - * comedi_config time, hence range can not be determined - */ - dev->open = dt9812_comedi_open; - - devpriv->serial = it->options[0]; - - /* Allocate subdevices */ - if (alloc_subdevices(dev, 4) < 0) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - /* digital input subdevice */ - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_read = &dt9812_di_rinsn; - - /* digital output subdevice */ - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_write = &dt9812_do_winsn; - - /* analog input subdevice */ - s = dev->subdevices + 2; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = NULL; - s->insn_read = &dt9812_ai_rinsn; - - /* analog output subdevice */ - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = NULL; - s->insn_write = &dt9812_ao_winsn; - s->insn_read = &dt9812_ao_rinsn; - - printk(KERN_INFO "comedi%d: successfully attached to dt9812.\n", - dev->minor); - - down(&dt9812_mutex); - /* Find a slot for the comedi device */ - { - struct slot_dt9812 *first = NULL; - struct slot_dt9812 *best = NULL; - for (i = 0; i < DT9812_NUM_SLOTS; i++) { - if (!first && !dt9812[i].comedi) { - /* First free slot from comedi side */ - first = &dt9812[i]; - } - if (!best && - dt9812[i].usb && - dt9812[i].usb->serial == devpriv->serial) { - /* We have an attaced device with matching ID */ - best = &dt9812[i]; - } - } - if (!best) - best = first; - if (best) { - down(&best->mutex); - best->comedi = devpriv; - best->serial = devpriv->serial; - devpriv->slot = best; - up(&best->mutex); - } - } - up(&dt9812_mutex); + sema_init(&devpriv->sem, 1); + usb_set_intfdata(intf, devpriv); + + ret = dt9812_find_endpoints(dev); + if (ret) + return ret; + + ret = dt9812_reset_device(dev); + if (ret) + return ret; + + is_unipolar = (devpriv->device == DT9812_DEVID_DT9812_2PT5); + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* Digital Input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = dt9812_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = dt9812_do_insn_bits; + + /* Analog Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; + s->insn_read = dt9812_ai_insn_read; + + /* Analog Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = is_unipolar ? &range_unipolar2_5 : &range_bipolar10; + 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; return 0; } -static int dt9812_detach(struct comedi_device *dev) +static void dt9812_detach(struct comedi_device *dev) { - return 0; -} + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct dt9812_private *devpriv = dev->private; -static struct comedi_driver dt9812_comedi_driver = { - .module = THIS_MODULE, - .driver_name = "dt9812", - .attach = dt9812_attach, - .detach = dt9812_detach, -}; + if (!devpriv) + return; -static int __init usb_dt9812_init(void) -{ - int result, i; - - /* Initialize all driver slots */ - for (i = 0; i < DT9812_NUM_SLOTS; i++) { - sema_init(&dt9812[i].mutex, 1); - dt9812[i].serial = 0; - dt9812[i].usb = NULL; - dt9812[i].comedi = NULL; - } - dt9812[12].serial = 0x0; - - /* register with the USB subsystem */ - result = usb_register(&dt9812_usb_driver); - if (result) { - printk(KERN_ERR KBUILD_MODNAME - ": usb_register failed. Error number %d\n", result); - return result; - } - /* register with comedi */ - result = comedi_driver_register(&dt9812_comedi_driver); - if (result) { - usb_deregister(&dt9812_usb_driver); - err("comedi_driver_register failed. Error number %d", result); - } + down(&devpriv->sem); - return result; + usb_set_intfdata(intf, NULL); + + up(&devpriv->sem); } -static void __exit usb_dt9812_exit(void) -{ - /* unregister with comedi */ - comedi_driver_unregister(&dt9812_comedi_driver); +static struct comedi_driver dt9812_driver = { + .driver_name = "dt9812", + .module = THIS_MODULE, + .auto_attach = dt9812_auto_attach, + .detach = dt9812_detach, +}; - /* deregister this driver with the USB subsystem */ - usb_deregister(&dt9812_usb_driver); +static int dt9812_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return comedi_usb_auto_config(intf, &dt9812_driver, id->driver_info); } -module_init(usb_dt9812_init); -module_exit(usb_dt9812_exit); +static const struct usb_device_id dt9812_usb_table[] = { + { USB_DEVICE(0x0867, 0x9812) }, + { } +}; +MODULE_DEVICE_TABLE(usb, dt9812_usb_table); + +static struct usb_driver dt9812_usb_driver = { + .name = "dt9812", + .id_table = dt9812_usb_table, + .probe = dt9812_usb_probe, + .disconnect = comedi_usb_auto_unconfig, +}; +module_comedi_usb_driver(dt9812_driver, dt9812_usb_driver); MODULE_AUTHOR("Anders Blomdell <anders.blomdell@control.lth.se>"); MODULE_DESCRIPTION("Comedi DT9812 driver"); diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c new file mode 100644 index 00000000000..e5593f8c740 --- /dev/null +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -0,0 +1,281 @@ +/* + * comedi/drivers/dyna_pci10xx.c + * Copyright (C) 2011 Prashant Shah, pshah.mumbai@gmail.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: dyna_pci10xx + Devices: Dynalog India PCI DAQ Cards, http://www.dynalogindia.com/ + Author: Prashant Shah <pshah.mumbai@gmail.com> + Developed at Automation Labs, Chemical Dept., IIT Bombay, India. + Prof. Kannan Moudgalya <kannan@iitb.ac.in> + http://www.iitb.ac.in + Status: Stable + Version: 1.0 + Device Supported : + - Dynalog PCI 1050 + + Notes : + - Dynalog India Pvt. Ltd. does not have a registered PCI Vendor ID and + they are using the PLX Technlogies Vendor ID since that is the PCI Chip used + in the card. + - Dynalog India Pvt. Ltd. has provided the internal register specification for + their cards in their manuals. +*/ + +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <linux/mutex.h> + +#include "../comedidev.h" + +#define READ_TIMEOUT 50 + +static const struct comedi_lrange range_pci1050_ai = { + 3, { + BIP_RANGE(10), + BIP_RANGE(5), + UNI_RANGE(10) + } +}; + +static const char range_codes_pci1050_ai[] = { 0x00, 0x10, 0x30 }; + +struct dyna_pci10xx_private { + struct mutex mutex; + unsigned long BADR3; +}; + +static int dyna_pci10xx_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw_p(dev->iobase); + if (status & (1 << 15)) + return 0; + return -EBUSY; +} + +static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct dyna_pci10xx_private *devpriv = dev->private; + int n; + u16 d = 0; + int ret = 0; + unsigned int chan, range; + + /* get the channel number and range */ + chan = CR_CHAN(insn->chanspec); + range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; + + mutex_lock(&devpriv->mutex); + /* convert n samples */ + for (n = 0; n < insn->n; n++) { + /* trigger conversion */ + smp_mb(); + outw_p(0x0000 + range + chan, dev->iobase + 2); + udelay(10); + + ret = comedi_timeout(dev, s, insn, dyna_pci10xx_ai_eoc, 0); + if (ret) + break; + + /* read data */ + d = inw_p(dev->iobase); + /* mask the first 4 bits - EOC bits */ + d &= 0x0FFF; + data[n] = d; + } + mutex_unlock(&devpriv->mutex); + + /* return the number of samples read/written */ + return ret ? ret : n; +} + +/* analog output callback */ +static int dyna_pci10xx_insn_write_ao(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct dyna_pci10xx_private *devpriv = dev->private; + int n; + unsigned int chan, range; + + chan = CR_CHAN(insn->chanspec); + range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; + + mutex_lock(&devpriv->mutex); + for (n = 0; n < insn->n; n++) { + smp_mb(); + /* trigger conversion and write data */ + outw_p(data[n], dev->iobase); + udelay(10); + } + mutex_unlock(&devpriv->mutex); + return n; +} + +/* digital input bit interface */ +static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct dyna_pci10xx_private *devpriv = dev->private; + u16 d = 0; + + mutex_lock(&devpriv->mutex); + smp_mb(); + d = inw_p(devpriv->BADR3); + udelay(10); + + /* on return the data[0] contains output and data[1] contains input */ + data[1] = d; + data[0] = s->state; + mutex_unlock(&devpriv->mutex); + return insn->n; +} + +static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct dyna_pci10xx_private *devpriv = dev->private; + + mutex_lock(&devpriv->mutex); + if (comedi_dio_update_state(s, data)) { + smp_mb(); + outw_p(s->state, devpriv->BADR3); + udelay(10); + } + + data[1] = s->state; + mutex_unlock(&devpriv->mutex); + + return insn->n; +} + +static int dyna_pci10xx_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct dyna_pci10xx_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; + dev->iobase = pci_resource_start(pcidev, 2); + devpriv->BADR3 = pci_resource_start(pcidev, 3); + + mutex_init(&devpriv->mutex); + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* analog input */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = 0x0FFF; + s->range_table = &range_pci1050_ai; + s->len_chanlist = 16; + s->insn_read = dyna_pci10xx_insn_read_ai; + + /* analog output */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 0x0FFF; + s->range_table = &range_unipolar10; + s->len_chanlist = 16; + s->insn_write = dyna_pci10xx_insn_write_ao; + + /* digital input */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->len_chanlist = 16; + s->insn_bits = dyna_pci10xx_di_insn_bits; + + /* digital output */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->len_chanlist = 16; + s->state = 0; + s->insn_bits = dyna_pci10xx_do_insn_bits; + + return 0; +} + +static void dyna_pci10xx_detach(struct comedi_device *dev) +{ + struct dyna_pci10xx_private *devpriv = dev->private; + + if (devpriv) + mutex_destroy(&devpriv->mutex); + comedi_pci_disable(dev); +} + +static struct comedi_driver dyna_pci10xx_driver = { + .driver_name = "dyna_pci10xx", + .module = THIS_MODULE, + .auto_attach = dyna_pci10xx_auto_attach, + .detach = dyna_pci10xx_detach, +}; + +static int dyna_pci10xx_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &dyna_pci10xx_driver, + id->driver_data); +} + +static const struct pci_device_id dyna_pci10xx_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_PLX, 0x1050) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, dyna_pci10xx_pci_table); + +static struct pci_driver dyna_pci10xx_pci_driver = { + .name = "dyna_pci10xx", + .id_table = dyna_pci10xx_pci_table, + .probe = dyna_pci10xx_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(dyna_pci10xx_driver, dyna_pci10xx_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Prashant Shah <pshah.mumbai@gmail.com>"); +MODULE_DESCRIPTION("Comedi based drivers for Dynalog PCI DAQ cards"); diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index 7f49add60b2..4e410f3b0e2 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -1,222 +1,178 @@ /* - comedi/drivers/fl512.c - Anders Gnistrup <ex18@kalman.iau.dtu.dk> -*/ + * fl512.c + * Anders Gnistrup <ex18@kalman.iau.dtu.dk> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* -Driver: fl512 -Description: unknown -Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk> -Devices: [unknown] FL512 (fl512) -Status: unknown - -Digital I/O is not supported. - -Configuration options: - [0] - I/O port base address -*/ - -#define DEBUG 0 + * Driver: fl512 + * Description: unknown + * Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk> + * Devices: [unknown] FL512 (fl512) + * Status: unknown + * + * Digital I/O is not supported. + * + * Configuration options: + * [0] - I/O port base address + */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/ioport.h> -#define FL512_SIZE 16 /* the size of the used memory */ -struct fl512_private { - - short ao_readback[2]; -}; +/* + * Register I/O map + */ +#define FL512_AI_LSB_REG 0x02 +#define FL512_AI_MSB_REG 0x03 +#define FL512_AI_MUX_REG 0x02 +#define FL512_AI_START_CONV_REG 0x03 +#define FL512_AO_DATA_REG(x) (0x04 + ((x) * 2)) +#define FL512_AO_TRIG_REG(x) (0x04 + ((x) * 2)) -#define devpriv ((struct fl512_private *) dev->private) - -static const struct comedi_lrange range_fl512 = { 4, { - BIP_RANGE(0.5), - BIP_RANGE(1), - BIP_RANGE(5), - BIP_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(5), - UNI_RANGE(10), - } +struct fl512_private { + unsigned short ao_readback[2]; }; -static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int fl512_detach(struct comedi_device *dev); - -static struct comedi_driver driver_fl512 = { - .driver_name = "fl512", - .module = THIS_MODULE, - .attach = fl512_attach, - .detach = fl512_detach, +static const struct comedi_lrange range_fl512 = { + 4, { + BIP_RANGE(0.5), + BIP_RANGE(1), + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(5), + UNI_RANGE(10) + } }; -static int __init driver_fl512_init_module(void) +static int fl512_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - return comedi_driver_register(&driver_fl512); -} + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; -static void __exit driver_fl512_cleanup_module(void) -{ - comedi_driver_unregister(&driver_fl512); -} - -module_init(driver_fl512_init_module); -module_exit(driver_fl512_cleanup_module); + outb(chan, dev->iobase + FL512_AI_MUX_REG); -static int fl512_ai_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int fl512_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int fl512_ao_insn_readback(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + for (i = 0; i < insn->n; i++) { + outb(0, dev->iobase + FL512_AI_START_CONV_REG); -/* - * fl512_ai_insn : this is the analog input function - */ -static int fl512_ai_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int n; - unsigned int lo_byte, hi_byte; - char chan = CR_CHAN(insn->chanspec); - unsigned long iobase = dev->iobase; - - for (n = 0; n < insn->n; n++) { /* sample n times on selected channel */ - /* XXX probably can move next step out of for() loop -- will - * make AI a little bit faster. */ - outb(chan, iobase + 2); /* select chan */ - outb(0, iobase + 3); /* start conversion */ /* XXX should test "done" flag instead of delay */ - udelay(30); /* sleep 30 usec */ - lo_byte = inb(iobase + 2); /* low 8 byte */ - hi_byte = inb(iobase + 3) & 0xf; /* high 4 bit and mask */ - data[n] = lo_byte + (hi_byte << 8); + udelay(30); + + val = inb(dev->iobase + FL512_AI_LSB_REG); + val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8); + val &= s->maxdata; + + data[i] = val; } - return n; + + return insn->n; } -/* - * fl512_ao_insn : used to write to a DA port n times - */ -static int fl512_ao_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int fl512_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - int chan = CR_CHAN(insn->chanspec); /* get chan to write */ - unsigned long iobase = dev->iobase; /* get base address */ - - for (n = 0; n < insn->n; n++) { /* write n data set */ - /* write low byte */ - outb(data[n] & 0x0ff, iobase + 4 + 2 * chan); - /* write high byte */ - outb((data[n] & 0xf00) >> 8, iobase + 4 + 2 * chan); - inb(iobase + 4 + 2 * chan); /* trig */ - - devpriv->ao_readback[chan] = data[n]; + struct fl512_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* write LSB, MSB then trigger conversion */ + outb(val & 0x0ff, dev->iobase + FL512_AO_DATA_REG(chan)); + outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan)); + inb(dev->iobase + FL512_AO_TRIG_REG(chan)); } - return n; + devpriv->ao_readback[chan] = val; + + return insn->n; } -/* - * fl512_ao_insn_readback : used to read previous values written to - * DA port - */ -static int fl512_ao_insn_readback(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int fl512_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - int chan = CR_CHAN(insn->chanspec); + struct fl512_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - return n; + return insn->n; } -/* - * start attach - */ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - unsigned long iobase; - - /* pointer to the subdevice: Analog in, Analog out, - (not made ->and Digital IO) */ + struct fl512_private *devpriv; struct comedi_subdevice *s; + int ret; - iobase = it->options[0]; - printk(KERN_INFO "comedi:%d fl512: 0x%04lx", dev->minor, iobase); - if (!request_region(iobase, FL512_SIZE, "fl512")) { - printk(KERN_WARNING " I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - dev->board_name = "fl512"; - if (alloc_private(dev, sizeof(struct fl512_private)) < 0) - return -ENOMEM; - -#if DEBUG - printk(KERN_DEBUG "malloc ok\n"); -#endif + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; - if (alloc_subdevices(dev, 2) < 0) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - /* - * this if the definitions of the supdevices, 2 have been defined - */ - /* Analog indput */ - s = dev->subdevices + 0; - /* define subdevice as Analog In */ - s->type = COMEDI_SUBD_AI; - /* you can read it from userspace */ - s->subdev_flags = SDF_READABLE | SDF_GROUND; - /* Number of Analog input channels */ - s->n_chan = 16; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when read AD */ - s->insn_read = fl512_ai_insn; - printk(KERN_INFO "comedi: fl512: subdevice 0 initialized\n"); - - /* Analog output */ - s = dev->subdevices + 1; - /* define subdevice as Analog OUT */ - s->type = COMEDI_SUBD_AO; - /* you can write it from userspace */ - s->subdev_flags = SDF_WRITABLE; - /* Number of Analog output channels */ - s->n_chan = 2; - /* accept only 12 bits of data */ - s->maxdata = 0x0fff; - /* device use one of the ranges */ - s->range_table = &range_fl512; - /* function to call when write DA */ - s->insn_write = fl512_ao_insn; - /* function to call when reading DA */ - s->insn_read = fl512_ao_insn_readback; - printk(KERN_INFO "comedi: fl512: subdevice 1 initialized\n"); - - return 1; -} + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_read = fl512_ai_insn_read; + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_fl512; + s->insn_write = fl512_ao_insn_write; + s->insn_read = fl512_ao_insn_read; -static int fl512_detach(struct comedi_device *dev) -{ - if (dev->iobase) - release_region(dev->iobase, FL512_SIZE); - printk(KERN_INFO "comedi%d: fl512: dummy i detach\n", dev->minor); return 0; } +static struct comedi_driver fl512_driver = { + .driver_name = "fl512", + .module = THIS_MODULE, + .attach = fl512_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(fl512_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index bc020dea141..22333c1ad88 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -1,315 +1,154 @@ /* - comedi/drivers/gsc_hpdi.c - This is a driver for the General Standards Corporation High - Speed Parallel Digital Interface rs485 boards. - - Author: Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2003 Coherent Imaging Systems - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************/ + * gsc_hpdi.c + * Comedi driver the General Standards Corporation + * High Speed Parallel Digital Interface rs485 boards. + * + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Copyright (C) 2003 Coherent Imaging Systems + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* + * Driver: gsc_hpdi + * Description: General Standards Corporation High + * Speed Parallel Digital Interface rs485 boards + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Status: only receive mode works, transmit not supported + * Updated: Thu, 01 Nov 2012 16:17:38 +0000 + * Devices: [General Standards Corporation] PCI-HPDI32 (gsc_hpdi), + * PMC-HPDI32 + * + * Configuration options: + * None. + * + * Manual configuration of supported devices is not supported; they are + * configured automatically. + * + * There are some additional hpdi models available from GSC for which + * support could be added to this driver. + */ -Driver: gsc_hpdi -Description: General Standards Corporation High - Speed Parallel Digital Interface rs485 boards -Author: Frank Mori Hess <fmhess@users.sourceforge.net> -Status: only receive mode works, transmit not supported -Updated: 2003-02-20 -Devices: [General Standards Corporation] PCI-HPDI32 (gsc_hpdi), - PMC-HPDI32 - -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - -There are some additional hpdi models available from GSC for which -support could be added to this driver. - -*/ - +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> #include <linux/interrupt.h> + #include "../comedidev.h" -#include <linux/delay.h> -#include "comedi_pci.h" #include "plx9080.h" #include "comedi_fc.h" -static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int hpdi_detach(struct comedi_device *dev); -static void abort_dma(struct comedi_device *dev, unsigned int channel); -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t handle_interrupt(int irq, void *d); -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data); - -#undef HPDI_DEBUG /* disable debugging messages */ -/* #define HPDI_DEBUG enable debugging code */ - -#ifdef HPDI_DEBUG -#define DEBUG_PRINT(format, args...) printk(format , ## args) -#else -#define DEBUG_PRINT(format, args...) -#endif - -#define TIMER_BASE 50 /* 20MHz master clock */ -#define DMA_BUFFER_SIZE 0x10000 -#define NUM_DMA_BUFFERS 4 -#define NUM_DMA_DESCRIPTORS 256 - -/* indices of base address regions */ -enum base_address_regions { - PLX9080_BADDRINDEX = 0, - HPDI_BADDRINDEX = 2, -}; - -enum hpdi_registers { - FIRMWARE_REV_REG = 0x0, - BOARD_CONTROL_REG = 0x4, - BOARD_STATUS_REG = 0x8, - TX_PROG_ALMOST_REG = 0xc, - RX_PROG_ALMOST_REG = 0x10, - FEATURES_REG = 0x14, - FIFO_REG = 0x18, - TX_STATUS_COUNT_REG = 0x1c, - TX_LINE_VALID_COUNT_REG = 0x20, - TX_LINE_INVALID_COUNT_REG = 0x24, - RX_STATUS_COUNT_REG = 0x28, - RX_LINE_COUNT_REG = 0x2c, - INTERRUPT_CONTROL_REG = 0x30, - INTERRUPT_STATUS_REG = 0x34, - TX_CLOCK_DIVIDER_REG = 0x38, - TX_FIFO_SIZE_REG = 0x40, - RX_FIFO_SIZE_REG = 0x44, - TX_FIFO_WORDS_REG = 0x48, - RX_FIFO_WORDS_REG = 0x4c, - INTERRUPT_EDGE_LEVEL_REG = 0x50, - INTERRUPT_POLARITY_REG = 0x54, -}; - -int command_channel_valid(unsigned int channel) -{ - if (channel == 0 || channel > 6) { - printk(KERN_WARNING - "gsc_hpdi: bug! invalid cable command channel\n"); - return 0; - } - return 1; -} - -/* bit definitions */ - -enum firmware_revision_bits { - FEATURES_REG_PRESENT_BIT = 0x8000, -}; -int firmware_revision(uint32_t fwr_bits) -{ - return fwr_bits & 0xff; -} - -int pcb_revision(uint32_t fwr_bits) -{ - return (fwr_bits >> 8) & 0xff; -} - -int hpdi_subid(uint32_t fwr_bits) -{ - return (fwr_bits >> 16) & 0xff; -} - -enum board_control_bits { - BOARD_RESET_BIT = 0x1, /* wait 10usec before accessing fifos */ - TX_FIFO_RESET_BIT = 0x2, - RX_FIFO_RESET_BIT = 0x4, - TX_ENABLE_BIT = 0x10, - RX_ENABLE_BIT = 0x20, - DEMAND_DMA_DIRECTION_TX_BIT = 0x40, - /* for ch 0, ch 1 can only transmit (when present) */ - LINE_VALID_ON_STATUS_VALID_BIT = 0x80, - START_TX_BIT = 0x10, - CABLE_THROTTLE_ENABLE_BIT = 0x20, - TEST_MODE_ENABLE_BIT = 0x80000000, -}; -uint32_t command_discrete_output_bits(unsigned int channel, int output, - int output_value) -{ - uint32_t bits = 0; - - if (command_channel_valid(channel) == 0) - return 0; - if (output) { - bits |= 0x1 << (16 + channel); - if (output_value) - bits |= 0x1 << (24 + channel); - } else - bits |= 0x1 << (24 + channel); - - return bits; -} - -enum board_status_bits { - COMMAND_LINE_STATUS_MASK = 0x7f, - TX_IN_PROGRESS_BIT = 0x80, - TX_NOT_EMPTY_BIT = 0x100, - TX_NOT_ALMOST_EMPTY_BIT = 0x200, - TX_NOT_ALMOST_FULL_BIT = 0x400, - TX_NOT_FULL_BIT = 0x800, - RX_NOT_EMPTY_BIT = 0x1000, - RX_NOT_ALMOST_EMPTY_BIT = 0x2000, - RX_NOT_ALMOST_FULL_BIT = 0x4000, - RX_NOT_FULL_BIT = 0x8000, - BOARD_JUMPER0_INSTALLED_BIT = 0x10000, - BOARD_JUMPER1_INSTALLED_BIT = 0x20000, - TX_OVERRUN_BIT = 0x200000, - RX_UNDERRUN_BIT = 0x400000, - RX_OVERRUN_BIT = 0x800000, -}; - -uint32_t almost_full_bits(unsigned int num_words) -{ -/* XXX need to add or subtract one? */ - return (num_words << 16) & 0xff0000; -} - -uint32_t almost_empty_bits(unsigned int num_words) -{ - return num_words & 0xffff; -} - -unsigned int almost_full_num_words(uint32_t bits) -{ -/* XXX need to add or subtract one? */ - return (bits >> 16) & 0xffff; -} - -unsigned int almost_empty_num_words(uint32_t bits) -{ - return bits & 0xffff; -} - -enum features_bits { - FIFO_SIZE_PRESENT_BIT = 0x1, - FIFO_WORDS_PRESENT_BIT = 0x2, - LEVEL_EDGE_INTERRUPTS_PRESENT_BIT = 0x4, - GPIO_SUPPORTED_BIT = 0x8, - PLX_DMA_CH1_SUPPORTED_BIT = 0x10, - OVERRUN_UNDERRUN_SUPPORTED_BIT = 0x20, -}; - -enum interrupt_sources { - FRAME_VALID_START_INTR = 0, - FRAME_VALID_END_INTR = 1, - TX_FIFO_EMPTY_INTR = 8, - TX_FIFO_ALMOST_EMPTY_INTR = 9, - TX_FIFO_ALMOST_FULL_INTR = 10, - TX_FIFO_FULL_INTR = 11, - RX_EMPTY_INTR = 12, - RX_ALMOST_EMPTY_INTR = 13, - RX_ALMOST_FULL_INTR = 14, - RX_FULL_INTR = 15, -}; -int command_intr_source(unsigned int channel) -{ - if (command_channel_valid(channel) == 0) - channel = 1; - return channel + 1; -} - -uint32_t intr_bit(int interrupt_source) -{ - return 0x1 << interrupt_source; -} - -uint32_t tx_clock_divisor_bits(unsigned int divisor) -{ - return divisor & 0xff; -} - -unsigned int fifo_size(uint32_t fifo_size_bits) -{ - return fifo_size_bits & 0xfffff; -} - -unsigned int fifo_words(uint32_t fifo_words_bits) -{ - return fifo_words_bits & 0xfffff; -} - -uint32_t intr_edge_bit(int interrupt_source) -{ - return 0x1 << interrupt_source; -} - -uint32_t intr_active_high_bit(int interrupt_source) -{ - return 0x1 << interrupt_source; -} +/* + * PCI BAR2 Register map (devpriv->mmio) + */ +#define FIRMWARE_REV_REG 0x00 +#define FEATURES_REG_PRESENT_BIT (1 << 15) +#define BOARD_CONTROL_REG 0x04 +#define BOARD_RESET_BIT (1 << 0) +#define TX_FIFO_RESET_BIT (1 << 1) +#define RX_FIFO_RESET_BIT (1 << 2) +#define TX_ENABLE_BIT (1 << 4) +#define RX_ENABLE_BIT (1 << 5) +#define DEMAND_DMA_DIRECTION_TX_BIT (1 << 6) /* ch 0 only */ +#define LINE_VALID_ON_STATUS_VALID_BIT (1 << 7) +#define START_TX_BIT (1 << 8) +#define CABLE_THROTTLE_ENABLE_BIT (1 << 9) +#define TEST_MODE_ENABLE_BIT (1 << 31) +#define BOARD_STATUS_REG 0x08 +#define COMMAND_LINE_STATUS_MASK (0x7f << 0) +#define TX_IN_PROGRESS_BIT (1 << 7) +#define TX_NOT_EMPTY_BIT (1 << 8) +#define TX_NOT_ALMOST_EMPTY_BIT (1 << 9) +#define TX_NOT_ALMOST_FULL_BIT (1 << 10) +#define TX_NOT_FULL_BIT (1 << 11) +#define RX_NOT_EMPTY_BIT (1 << 12) +#define RX_NOT_ALMOST_EMPTY_BIT (1 << 13) +#define RX_NOT_ALMOST_FULL_BIT (1 << 14) +#define RX_NOT_FULL_BIT (1 << 15) +#define BOARD_JUMPER0_INSTALLED_BIT (1 << 16) +#define BOARD_JUMPER1_INSTALLED_BIT (1 << 17) +#define TX_OVERRUN_BIT (1 << 21) +#define RX_UNDERRUN_BIT (1 << 22) +#define RX_OVERRUN_BIT (1 << 23) +#define TX_PROG_ALMOST_REG 0x0c +#define RX_PROG_ALMOST_REG 0x10 +#define ALMOST_EMPTY_BITS(x) (((x) & 0xffff) << 0) +#define ALMOST_FULL_BITS(x) (((x) & 0xff) << 16) +#define FEATURES_REG 0x14 +#define FIFO_SIZE_PRESENT_BIT (1 << 0) +#define FIFO_WORDS_PRESENT_BIT (1 << 1) +#define LEVEL_EDGE_INTERRUPTS_PRESENT_BIT (1 << 2) +#define GPIO_SUPPORTED_BIT (1 << 3) +#define PLX_DMA_CH1_SUPPORTED_BIT (1 << 4) +#define OVERRUN_UNDERRUN_SUPPORTED_BIT (1 << 5) +#define FIFO_REG 0x18 +#define TX_STATUS_COUNT_REG 0x1c +#define TX_LINE_VALID_COUNT_REG 0x20, +#define TX_LINE_INVALID_COUNT_REG 0x24 +#define RX_STATUS_COUNT_REG 0x28 +#define RX_LINE_COUNT_REG 0x2c +#define INTERRUPT_CONTROL_REG 0x30 +#define FRAME_VALID_START_INTR (1 << 0) +#define FRAME_VALID_END_INTR (1 << 1) +#define TX_FIFO_EMPTY_INTR (1 << 8) +#define TX_FIFO_ALMOST_EMPTY_INTR (1 << 9) +#define TX_FIFO_ALMOST_FULL_INTR (1 << 10) +#define TX_FIFO_FULL_INTR (1 << 11) +#define RX_EMPTY_INTR (1 << 12) +#define RX_ALMOST_EMPTY_INTR (1 << 13) +#define RX_ALMOST_FULL_INTR (1 << 14) +#define RX_FULL_INTR (1 << 15) +#define INTERRUPT_STATUS_REG 0x34 +#define TX_CLOCK_DIVIDER_REG 0x38 +#define TX_FIFO_SIZE_REG 0x40 +#define RX_FIFO_SIZE_REG 0x44 +#define FIFO_SIZE_MASK (0xfffff << 0) +#define TX_FIFO_WORDS_REG 0x48 +#define RX_FIFO_WORDS_REG 0x4c +#define INTERRUPT_EDGE_LEVEL_REG 0x50 +#define INTERRUPT_POLARITY_REG 0x54 + +#define TIMER_BASE 50 /* 20MHz master clock */ +#define DMA_BUFFER_SIZE 0x10000 +#define NUM_DMA_BUFFERS 4 +#define NUM_DMA_DESCRIPTORS 256 struct hpdi_board { - - char *name; - int device_id; /* pci device id */ - int subdevice_id; /* pci subdevice id */ + const char *name; + int device_id; + int subdevice_id; }; static const struct hpdi_board hpdi_boards[] = { { - .name = "pci-hpdi32", - .device_id = PCI_DEVICE_ID_PLX_9080, - .subdevice_id = 0x2400, + .name = "pci-hpdi32", + .device_id = PCI_DEVICE_ID_PLX_9080, + .subdevice_id = 0x2400, }, #if 0 { - .name = "pxi-hpdi32", - .device_id = 0x9656, - .subdevice_id = 0x2705, + .name = "pxi-hpdi32", + .device_id = 0x9656, + .subdevice_id = 0x2705, }, #endif }; -static DEFINE_PCI_DEVICE_TABLE(hpdi_pci_table) = { - { - PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX, - 0x2400, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, hpdi_pci_table); - -static inline struct hpdi_board *board(const struct comedi_device *dev) -{ - return (struct hpdi_board *)dev->board_ptr; -} - struct hpdi_private { - - struct pci_dev *hw_dev; /* pointer to board's pci_dev struct */ - /* base addresses (physical) */ - resource_size_t plx9080_phys_iobase; - resource_size_t hpdi_phys_iobase; - /* base addresses (ioremapped) */ - void *plx9080_iobase; - void *hpdi_iobase; + void __iomem *plx9080_mmio; + void __iomem *mmio; uint32_t *dio_buffer[NUM_DMA_BUFFERS]; /* dma buffers */ /* physical addresses of dma buffers */ dma_addr_t dio_buffer_phys_addr[NUM_DMA_BUFFERS]; @@ -322,535 +161,267 @@ struct hpdi_private { /* pointer to start of buffers indexed by descriptor */ uint32_t *desc_dio_buffer[NUM_DMA_DESCRIPTORS]; /* index of the dma descriptor that is currently being used */ - volatile unsigned int dma_desc_index; + unsigned int dma_desc_index; unsigned int tx_fifo_size; unsigned int rx_fifo_size; - volatile unsigned long dio_count; - /* software copies of values written to hpdi registers */ - volatile uint32_t bits[24]; + unsigned long dio_count; /* number of bytes at which to generate COMEDI_CB_BLOCK events */ - volatile unsigned int block_size; - unsigned dio_config_output:1; + unsigned int block_size; }; -static inline struct hpdi_private *priv(struct comedi_device *dev) +static void gsc_hpdi_drain_dma(struct comedi_device *dev, unsigned int channel) { - return dev->private; -} + struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int idx; + unsigned int start; + unsigned int desc; + unsigned int size; + unsigned int next; -static struct comedi_driver driver_hpdi = { - .driver_name = "gsc_hpdi", - .module = THIS_MODULE, - .attach = hpdi_attach, - .detach = hpdi_detach, -}; + if (channel) + next = readl(devpriv->plx9080_mmio + PLX_DMA1_PCI_ADDRESS_REG); + else + next = readl(devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + + idx = devpriv->dma_desc_index; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); + /* loop until we have read all the full buffers */ + for (desc = 0; (next < start || next >= start + devpriv->block_size) && + desc < devpriv->num_dma_descriptors; desc++) { + /* transfer data from dma buffer to comedi buffer */ + size = devpriv->block_size / sizeof(uint32_t); + if (cmd->stop_src == TRIG_COUNT) { + if (size > devpriv->dio_count) + size = devpriv->dio_count; + devpriv->dio_count -= size; + } + cfc_write_array_to_buffer(s, devpriv->desc_dio_buffer[idx], + size * sizeof(uint32_t)); + idx++; + idx %= devpriv->num_dma_descriptors; + start = le32_to_cpu(devpriv->dma_desc[idx].pci_start_addr); -static int __devinit driver_hpdi_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_hpdi.driver_name); + devpriv->dma_desc_index = idx; + } + /* XXX check for buffer overrun somehow */ } -static void __devexit driver_hpdi_pci_remove(struct pci_dev *dev) +static irqreturn_t gsc_hpdi_interrupt(int irq, void *d) { - comedi_pci_auto_unconfig(dev); -} + struct comedi_device *dev = d; + struct hpdi_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + uint32_t hpdi_intr_status, hpdi_board_status; + uint32_t plx_status; + uint32_t plx_bits; + uint8_t dma0_status, dma1_status; + unsigned long flags; -static struct pci_driver driver_hpdi_pci_driver = { - .id_table = hpdi_pci_table, - .probe = &driver_hpdi_pci_probe, - .remove = __devexit_p(&driver_hpdi_pci_remove) -}; + if (!dev->attached) + return IRQ_NONE; -static int __init driver_hpdi_init_module(void) -{ - int retval; + plx_status = readl(devpriv->plx9080_mmio + PLX_INTRCS_REG); + if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) + return IRQ_NONE; - retval = comedi_driver_register(&driver_hpdi); - if (retval < 0) - return retval; + hpdi_intr_status = readl(devpriv->mmio + INTERRUPT_STATUS_REG); + hpdi_board_status = readl(devpriv->mmio + BOARD_STATUS_REG); - driver_hpdi_pci_driver.name = (char *)driver_hpdi.driver_name; - return pci_register_driver(&driver_hpdi_pci_driver); -} + if (hpdi_intr_status) + writel(hpdi_intr_status, devpriv->mmio + INTERRUPT_STATUS_REG); -static void __exit driver_hpdi_cleanup_module(void) -{ - pci_unregister_driver(&driver_hpdi_pci_driver); - comedi_driver_unregister(&driver_hpdi); -} + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma0_status = readb(devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ + writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); -module_init(driver_hpdi_init_module); -module_exit(driver_hpdi_cleanup_module); + if (dma0_status & PLX_DMA_EN_BIT) + gsc_hpdi_drain_dma(dev, 0); + } + spin_unlock_irqrestore(&dev->spinlock, flags); -static int dio_config_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - priv(dev)->dio_config_output = 1; - return insn->n; - break; - case INSN_CONFIG_DIO_INPUT: - priv(dev)->dio_config_output = 0; - return insn->n; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - priv(dev)->dio_config_output ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - case INSN_CONFIG_BLOCK_SIZE: - return dio_config_block_size(dev, data); - break; - default: - break; + /* spin lock makes sure no one else changes plx dma control reg */ + spin_lock_irqsave(&dev->spinlock, flags); + dma1_status = readb(devpriv->plx9080_mmio + PLX_DMA1_CS_REG); + if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ + writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA1_CS_REG); } + spin_unlock_irqrestore(&dev->spinlock, flags); - return -EINVAL; -} + /* clear possible plx9080 interrupt sources */ + if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ + plx_bits = readl(devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + writel(plx_bits, devpriv->plx9080_mmio + PLX_DBR_OUT_REG); + } -static void disable_plx_interrupts(struct comedi_device *dev) -{ - writel(0, priv(dev)->plx9080_iobase + PLX_INTRCS_REG); -} + if (hpdi_board_status & RX_OVERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo overrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } -/* initialize plx9080 chip */ -static void init_plx9080(struct comedi_device *dev) -{ - uint32_t bits; - void *plx_iobase = priv(dev)->plx9080_iobase; - - /* plx9080 dump */ - DEBUG_PRINT(" plx interrupt status 0x%x\n", - readl(plx_iobase + PLX_INTRCS_REG)); - DEBUG_PRINT(" plx id bits 0x%x\n", readl(plx_iobase + PLX_ID_REG)); - DEBUG_PRINT(" plx control reg 0x%x\n", - readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG)); - - DEBUG_PRINT(" plx revision 0x%x\n", - readl(plx_iobase + PLX_REVISION_REG)); - DEBUG_PRINT(" plx dma channel 0 mode 0x%x\n", - readl(plx_iobase + PLX_DMA0_MODE_REG)); - DEBUG_PRINT(" plx dma channel 1 mode 0x%x\n", - readl(plx_iobase + PLX_DMA1_MODE_REG)); - DEBUG_PRINT(" plx dma channel 0 pci address 0x%x\n", - readl(plx_iobase + PLX_DMA0_PCI_ADDRESS_REG)); - DEBUG_PRINT(" plx dma channel 0 local address 0x%x\n", - readl(plx_iobase + PLX_DMA0_LOCAL_ADDRESS_REG)); - DEBUG_PRINT(" plx dma channel 0 transfer size 0x%x\n", - readl(plx_iobase + PLX_DMA0_TRANSFER_SIZE_REG)); - DEBUG_PRINT(" plx dma channel 0 descriptor 0x%x\n", - readl(plx_iobase + PLX_DMA0_DESCRIPTOR_REG)); - DEBUG_PRINT(" plx dma channel 0 command status 0x%x\n", - readb(plx_iobase + PLX_DMA0_CS_REG)); - DEBUG_PRINT(" plx dma channel 0 threshold 0x%x\n", - readl(plx_iobase + PLX_DMA0_THRESHOLD_REG)); - DEBUG_PRINT(" plx bigend 0x%x\n", readl(plx_iobase + PLX_BIGEND_REG)); -#ifdef __BIG_ENDIAN - bits = BIGEND_DMA0 | BIGEND_DMA1; -#else - bits = 0; -#endif - writel(bits, priv(dev)->plx9080_iobase + PLX_BIGEND_REG); + if (hpdi_board_status & RX_UNDERRUN_BIT) { + dev_err(dev->class_dev, "rx fifo underrun\n"); + async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + } - disable_plx_interrupts(dev); + if (devpriv->dio_count == 0) + async->events |= COMEDI_CB_EOA; - abort_dma(dev, 0); - abort_dma(dev, 1); + cfc_handle_events(dev, s); - /* configure dma0 mode */ - bits = 0; - /* enable ready input */ - bits |= PLX_DMA_EN_READYIN_BIT; - /* enable dma chaining */ - bits |= PLX_EN_CHAIN_BIT; - /* enable interrupt on dma done - * (probably don't need this, since chain never finishes) */ - bits |= PLX_EN_DMA_DONE_INTR_BIT; - /* don't increment local address during transfers - * (we are transferring from a fixed fifo register) */ - bits |= PLX_LOCAL_ADDR_CONST_BIT; - /* route dma interrupt to pci bus */ - bits |= PLX_DMA_INTR_PCI_BIT; - /* enable demand mode */ - bits |= PLX_DEMAND_MODE_BIT; - /* enable local burst mode */ - bits |= PLX_DMA_LOCAL_BURST_EN_BIT; - bits |= PLX_LOCAL_BUS_32_WIDE_BITS; - writel(bits, plx_iobase + PLX_DMA0_MODE_REG); + return IRQ_HANDLED; } -/* Allocate and initialize the subdevice structures. - */ -static int setup_subdevices(struct comedi_device *dev) +static void gsc_hpdi_abort_dma(struct comedi_device *dev, unsigned int channel) { - struct comedi_subdevice *s; + struct hpdi_private *devpriv = dev->private; + unsigned long flags; - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; + /* spinlock for plx dma control/status reg */ + spin_lock_irqsave(&dev->spinlock, flags); - s = dev->subdevices + 0; - /* analog input subdevice */ - dev->read_subdev = s; -/* dev->write_subdev = s; */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | SDF_CMD_READ; - s->n_chan = 32; - s->len_chanlist = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = dio_config_insn; - s->do_cmd = hpdi_cmd; - s->do_cmdtest = hpdi_cmd_test; - s->cancel = hpdi_cancel; + plx9080_abort_dma(devpriv->plx9080_mmio, channel); - return 0; + spin_unlock_irqrestore(&dev->spinlock, flags); } -static int init_hpdi(struct comedi_device *dev) +static int gsc_hpdi_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - uint32_t plx_intcsr_bits; - - writel(BOARD_RESET_BIT, priv(dev)->hpdi_iobase + BOARD_CONTROL_REG); - udelay(10); - - writel(almost_empty_bits(32) | almost_full_bits(32), - priv(dev)->hpdi_iobase + RX_PROG_ALMOST_REG); - writel(almost_empty_bits(32) | almost_full_bits(32), - priv(dev)->hpdi_iobase + TX_PROG_ALMOST_REG); - - priv(dev)->tx_fifo_size = fifo_size(readl(priv(dev)->hpdi_iobase + - TX_FIFO_SIZE_REG)); - priv(dev)->rx_fifo_size = fifo_size(readl(priv(dev)->hpdi_iobase + - RX_FIFO_SIZE_REG)); + struct hpdi_private *devpriv = dev->private; - writel(0, priv(dev)->hpdi_iobase + INTERRUPT_CONTROL_REG); + writel(0, devpriv->mmio + BOARD_CONTROL_REG); + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); - /* enable interrupts */ - plx_intcsr_bits = - ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | - ICS_DMA0_E; - writel(plx_intcsr_bits, priv(dev)->plx9080_iobase + PLX_INTRCS_REG); + gsc_hpdi_abort_dma(dev, 0); return 0; } -/* setup dma descriptors so a link completes every 'transfer_size' bytes */ -static int setup_dma_descriptors(struct comedi_device *dev, - unsigned int transfer_size) -{ - unsigned int buffer_index, buffer_offset; - uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | - PLX_XFER_LOCAL_TO_PCI; - unsigned int i; - - if (transfer_size > DMA_BUFFER_SIZE) - transfer_size = DMA_BUFFER_SIZE; - transfer_size -= transfer_size % sizeof(uint32_t); - if (transfer_size == 0) - return -1; - - DEBUG_PRINT(" transfer_size %i\n", transfer_size); - DEBUG_PRINT(" descriptors at 0x%lx\n", - (unsigned long)priv(dev)->dma_desc_phys_addr); - - buffer_offset = 0; - buffer_index = 0; - for (i = 0; i < NUM_DMA_DESCRIPTORS && - buffer_index < NUM_DMA_BUFFERS; i++) { - priv(dev)->dma_desc[i].pci_start_addr = - cpu_to_le32(priv(dev)->dio_buffer_phys_addr[buffer_index] + - buffer_offset); - priv(dev)->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); - priv(dev)->dma_desc[i].transfer_size = - cpu_to_le32(transfer_size); - priv(dev)->dma_desc[i].next = - cpu_to_le32((priv(dev)->dma_desc_phys_addr + (i + - 1) * - sizeof(priv(dev)->dma_desc[0])) | next_bits); - - priv(dev)->desc_dio_buffer[i] = - priv(dev)->dio_buffer[buffer_index] + - (buffer_offset / sizeof(uint32_t)); - - buffer_offset += transfer_size; - if (transfer_size + buffer_offset > DMA_BUFFER_SIZE) { - buffer_offset = 0; - buffer_index++; - } - - DEBUG_PRINT(" desc %i\n", i); - DEBUG_PRINT(" start addr virt 0x%p, phys 0x%lx\n", - priv(dev)->desc_dio_buffer[i], - (unsigned long)priv(dev)->dma_desc[i]. - pci_start_addr); - DEBUG_PRINT(" next 0x%lx\n", - (unsigned long)priv(dev)->dma_desc[i].next); - } - priv(dev)->num_dma_descriptors = i; - /* fix last descriptor to point back to first */ - priv(dev)->dma_desc[i - 1].next = - cpu_to_le32(priv(dev)->dma_desc_phys_addr | next_bits); - DEBUG_PRINT(" desc %i next fixup 0x%lx\n", i - 1, - (unsigned long)priv(dev)->dma_desc[i - 1].next); - - priv(dev)->block_size = transfer_size; - - return transfer_size; -} - -static int hpdi_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int gsc_hpdi_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct pci_dev *pcidev; - int i; - int retval; - - printk(KERN_WARNING "comedi%d: gsc_hpdi\n", dev->minor); - - if (alloc_private(dev, sizeof(struct hpdi_private)) < 0) - return -ENOMEM; - - pcidev = NULL; - for (i = 0; i < ARRAY_SIZE(hpdi_boards) && - dev->board_ptr == NULL; i++) { - do { - pcidev = pci_get_subsys(PCI_VENDOR_ID_PLX, - hpdi_boards[i].device_id, - PCI_VENDOR_ID_PLX, - hpdi_boards[i].subdevice_id, - pcidev); - /* was a particular bus/slot requested? */ - if (it->options[0] || it->options[1]) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) - continue; - } - if (pcidev) { - priv(dev)->hw_dev = pcidev; - dev->board_ptr = hpdi_boards + i; - break; - } - } while (pcidev != NULL); - } - if (dev->board_ptr == NULL) { - printk(KERN_WARNING "gsc_hpdi: no hpdi card found\n"); - return -EIO; - } - - printk(KERN_WARNING - "gsc_hpdi: found %s on bus %i, slot %i\n", board(dev)->name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn)); + struct hpdi_private *devpriv = dev->private; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned long flags; + uint32_t bits; - if (comedi_pci_enable(pcidev, driver_hpdi.driver_name)) { - printk(KERN_WARNING - " failed enable PCI device and request regions\n"); - return -EIO; - } - pci_set_master(pcidev); + if (s->io_bits) + return -EINVAL; - /* Initialize dev->board_name */ - dev->board_name = board(dev)->name; - - priv(dev)->plx9080_phys_iobase = - pci_resource_start(pcidev, PLX9080_BADDRINDEX); - priv(dev)->hpdi_phys_iobase = - pci_resource_start(pcidev, HPDI_BADDRINDEX); - - /* remap, won't work with 2.0 kernels but who cares */ - priv(dev)->plx9080_iobase = ioremap(priv(dev)->plx9080_phys_iobase, - pci_resource_len(pcidev, - PLX9080_BADDRINDEX)); - priv(dev)->hpdi_iobase = - ioremap(priv(dev)->hpdi_phys_iobase, - pci_resource_len(pcidev, HPDI_BADDRINDEX)); - if (!priv(dev)->plx9080_iobase || !priv(dev)->hpdi_iobase) { - printk(KERN_WARNING " failed to remap io memory\n"); - return -ENOMEM; - } + writel(RX_FIFO_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); - DEBUG_PRINT(" plx9080 remapped to 0x%p\n", priv(dev)->plx9080_iobase); - DEBUG_PRINT(" hpdi remapped to 0x%p\n", priv(dev)->hpdi_iobase); + gsc_hpdi_abort_dma(dev, 0); - init_plx9080(dev); + devpriv->dma_desc_index = 0; - /* get irq */ - if (request_irq(pcidev->irq, handle_interrupt, IRQF_SHARED, - driver_hpdi.driver_name, dev)) { - printk(KERN_WARNING - " unable to allocate irq %u\n", pcidev->irq); - return -EINVAL; - } - dev->irq = pcidev->irq; + /* + * These register are supposedly unused during chained dma, + * but I have found that left over values from last operation + * occasionally cause problems with transfer of first dma + * block. Initializing them to zero seems to fix the problem. + */ + writel(0, devpriv->plx9080_mmio + PLX_DMA0_TRANSFER_SIZE_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_PCI_ADDRESS_REG); + writel(0, devpriv->plx9080_mmio + PLX_DMA0_LOCAL_ADDRESS_REG); + + /* give location of first dma descriptor */ + bits = devpriv->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | + PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; + writel(bits, devpriv->plx9080_mmio + PLX_DMA0_DESCRIPTOR_REG); + + /* enable dma transfer */ + spin_lock_irqsave(&dev->spinlock, flags); + writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, + devpriv->plx9080_mmio + PLX_DMA0_CS_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); - printk(KERN_WARNING " irq %u\n", dev->irq); + if (cmd->stop_src == TRIG_COUNT) + devpriv->dio_count = cmd->stop_arg; + else + devpriv->dio_count = 1; - /* alocate pci dma buffers */ - for (i = 0; i < NUM_DMA_BUFFERS; i++) { - priv(dev)->dio_buffer[i] = - pci_alloc_consistent(priv(dev)->hw_dev, DMA_BUFFER_SIZE, - &priv(dev)->dio_buffer_phys_addr[i]); - DEBUG_PRINT("dio_buffer at virt 0x%p, phys 0x%lx\n", - priv(dev)->dio_buffer[i], - (unsigned long)priv(dev)->dio_buffer_phys_addr[i]); - } - /* allocate dma descriptors */ - priv(dev)->dma_desc = pci_alloc_consistent(priv(dev)->hw_dev, - sizeof(struct plx_dma_desc) * - NUM_DMA_DESCRIPTORS, - &priv(dev)-> - dma_desc_phys_addr); - if (priv(dev)->dma_desc_phys_addr & 0xf) { - printk(KERN_WARNING - " dma descriptors not quad-word aligned (bug)\n"); - return -EIO; - } + /* clear over/under run status flags */ + writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, + devpriv->mmio + BOARD_STATUS_REG); - retval = setup_dma_descriptors(dev, 0x1000); - if (retval < 0) - return retval; + /* enable interrupts */ + writel(RX_FULL_INTR, devpriv->mmio + INTERRUPT_CONTROL_REG); - retval = setup_subdevices(dev); - if (retval < 0) - return retval; + writel(RX_ENABLE_BIT, devpriv->mmio + BOARD_CONTROL_REG); - return init_hpdi(dev); + return 0; } -static int hpdi_detach(struct comedi_device *dev) +static int gsc_hpdi_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - unsigned int i; + int i; - printk(KERN_WARNING "comedi%d: gsc_hpdi: remove\n", dev->minor); + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); - if (dev->irq) - free_irq(dev->irq, dev); - if ((priv(dev)) && (priv(dev)->hw_dev)) { - if (priv(dev)->plx9080_iobase) { - disable_plx_interrupts(dev); - iounmap((void *)priv(dev)->plx9080_iobase); - } - if (priv(dev)->hpdi_iobase) - iounmap((void *)priv(dev)->hpdi_iobase); - /* free pci dma buffers */ - for (i = 0; i < NUM_DMA_BUFFERS; i++) { - if (priv(dev)->dio_buffer[i]) - pci_free_consistent(priv(dev)->hw_dev, - DMA_BUFFER_SIZE, - priv(dev)-> - dio_buffer[i], - priv - (dev)->dio_buffer_phys_addr - [i]); + if (chan != i) { + dev_dbg(dev->class_dev, + "chanlist must be ch 0 to 31 in order\n"); + return -EINVAL; } - /* free dma descriptors */ - if (priv(dev)->dma_desc) - pci_free_consistent(priv(dev)->hw_dev, - sizeof(struct plx_dma_desc) - * NUM_DMA_DESCRIPTORS, - priv(dev)->dma_desc, - priv(dev)-> - dma_desc_phys_addr); - if (priv(dev)->hpdi_phys_iobase) - comedi_pci_disable(priv(dev)->hw_dev); - pci_dev_put(priv(dev)->hw_dev); } - return 0; -} - -static int dio_config_block_size(struct comedi_device *dev, unsigned int *data) -{ - unsigned int requested_block_size; - int retval; - requested_block_size = data[1]; - - retval = setup_dma_descriptors(dev, requested_block_size); - if (retval < 0) - return retval; - - data[1] = retval; - - return 2; + return 0; } -static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int gsc_hpdi_cmd_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; - int tmp; - int i; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + if (s->io_bits) + return -EINVAL; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - * compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* uniqueness check */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (!cmd->chanlist_len) { + if (!cmd->chanlist_len || !cmd->chanlist) { cmd->chanlist_len = 32; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; + err |= -EINVAL; } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - switch (cmd->stop_src) { - case TRIG_COUNT: - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - break; - case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - break; - default: - break; - } + 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; @@ -860,258 +431,320 @@ static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - if (!cmd->chanlist) - return 0; - - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != i) { - /* XXX could support 8 or 16 channels */ - comedi_error(dev, - "chanlist must be ch 0 to 31 in order"); - err++; - break; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= gsc_hpdi_check_chanlist(dev, s, cmd); if (err) return 5; return 0; + } -static int hpdi_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +/* setup dma descriptors so a link completes every 'len' bytes */ +static int gsc_hpdi_setup_dma_descriptors(struct comedi_device *dev, + unsigned int len) { - if (priv(dev)->dio_config_output) + struct hpdi_private *devpriv = dev->private; + dma_addr_t phys_addr = devpriv->dma_desc_phys_addr; + uint32_t next_bits = PLX_DESC_IN_PCI_BIT | PLX_INTR_TERM_COUNT | + PLX_XFER_LOCAL_TO_PCI; + unsigned int offset = 0; + unsigned int idx = 0; + unsigned int i; + + if (len > DMA_BUFFER_SIZE) + len = DMA_BUFFER_SIZE; + len -= len % sizeof(uint32_t); + if (len == 0) return -EINVAL; - else - return di_cmd_test(dev, s, cmd); -} -static inline void hpdi_writel(struct comedi_device *dev, uint32_t bits, - unsigned int offset) -{ - writel(bits | priv(dev)->bits[offset / sizeof(uint32_t)], - priv(dev)->hpdi_iobase + offset); + for (i = 0; i < NUM_DMA_DESCRIPTORS && idx < NUM_DMA_BUFFERS; i++) { + devpriv->dma_desc[i].pci_start_addr = + cpu_to_le32(devpriv->dio_buffer_phys_addr[idx] + offset); + devpriv->dma_desc[i].local_start_addr = cpu_to_le32(FIFO_REG); + devpriv->dma_desc[i].transfer_size = cpu_to_le32(len); + devpriv->dma_desc[i].next = cpu_to_le32((phys_addr + + (i + 1) * sizeof(devpriv->dma_desc[0])) | next_bits); + + devpriv->desc_dio_buffer[i] = devpriv->dio_buffer[idx] + + (offset / sizeof(uint32_t)); + + offset += len; + if (len + offset > DMA_BUFFER_SIZE) { + offset = 0; + idx++; + } + } + devpriv->num_dma_descriptors = i; + /* fix last descriptor to point back to first */ + devpriv->dma_desc[i - 1].next = cpu_to_le32(phys_addr | next_bits); + + devpriv->block_size = len; + + return len; } -static int di_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static int gsc_hpdi_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - uint32_t bits; - unsigned long flags; - struct comedi_async *async = s->async; - struct comedi_cmd *cmd = &async->cmd; + int ret; + + switch (data[0]) { + case INSN_CONFIG_BLOCK_SIZE: + ret = gsc_hpdi_setup_dma_descriptors(dev, data[1]); + if (ret) + return ret; - hpdi_writel(dev, RX_FIFO_RESET_BIT, BOARD_CONTROL_REG); + data[1] = ret; + break; + default: + ret = comedi_dio_insn_config(dev, s, insn, data, 0xffffffff); + if (ret) + return ret; + break; + } - DEBUG_PRINT("hpdi: in di_cmd\n"); + return insn->n; +} - abort_dma(dev, 0); +static int gsc_hpdi_init(struct comedi_device *dev) +{ + struct hpdi_private *devpriv = dev->private; + uint32_t plx_intcsr_bits; - priv(dev)->dma_desc_index = 0; + /* wait 10usec after reset before accessing fifos */ + writel(BOARD_RESET_BIT, devpriv->mmio + BOARD_CONTROL_REG); + udelay(10); - /* These register are supposedly unused during chained dma, - * but I have found that left over values from last operation - * occasionally cause problems with transfer of first dma - * block. Initializing them to zero seems to fix the problem. */ - writel(0, priv(dev)->plx9080_iobase + PLX_DMA0_TRANSFER_SIZE_REG); - writel(0, priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG); - writel(0, priv(dev)->plx9080_iobase + PLX_DMA0_LOCAL_ADDRESS_REG); - /* give location of first dma descriptor */ - bits = - priv(dev)->dma_desc_phys_addr | PLX_DESC_IN_PCI_BIT | - PLX_INTR_TERM_COUNT | PLX_XFER_LOCAL_TO_PCI; - writel(bits, priv(dev)->plx9080_iobase + PLX_DMA0_DESCRIPTOR_REG); + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + RX_PROG_ALMOST_REG); + writel(ALMOST_EMPTY_BITS(32) | ALMOST_FULL_BITS(32), + devpriv->mmio + TX_PROG_ALMOST_REG); - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - /* enable dma transfer */ - writeb(PLX_DMA_EN_BIT | PLX_DMA_START_BIT | PLX_CLEAR_DMA_INTR_BIT, - priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); + devpriv->tx_fifo_size = readl(devpriv->mmio + TX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; + devpriv->rx_fifo_size = readl(devpriv->mmio + RX_FIFO_SIZE_REG) & + FIFO_SIZE_MASK; - if (cmd->stop_src == TRIG_COUNT) - priv(dev)->dio_count = cmd->stop_arg; - else - priv(dev)->dio_count = 1; + writel(0, devpriv->mmio + INTERRUPT_CONTROL_REG); - /* clear over/under run status flags */ - writel(RX_UNDERRUN_BIT | RX_OVERRUN_BIT, - priv(dev)->hpdi_iobase + BOARD_STATUS_REG); /* enable interrupts */ - writel(intr_bit(RX_FULL_INTR), - priv(dev)->hpdi_iobase + INTERRUPT_CONTROL_REG); - - DEBUG_PRINT("hpdi: starting rx\n"); - hpdi_writel(dev, RX_ENABLE_BIT, BOARD_CONTROL_REG); + plx_intcsr_bits = + ICS_AERR | ICS_PERR | ICS_PIE | ICS_PLIE | ICS_PAIE | ICS_LIE | + ICS_DMA0_E; + writel(plx_intcsr_bits, devpriv->plx9080_mmio + PLX_INTRCS_REG); return 0; } -static int hpdi_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static void gsc_hpdi_init_plx9080(struct comedi_device *dev) { - if (priv(dev)->dio_config_output) - return -EINVAL; - else - return di_cmd(dev, s); -} + struct hpdi_private *devpriv = dev->private; + uint32_t bits; + void __iomem *plx_iobase = devpriv->plx9080_mmio; -static void drain_dma_buffers(struct comedi_device *dev, unsigned int channel) -{ - struct comedi_async *async = dev->read_subdev->async; - uint32_t next_transfer_addr; - int j; - int num_samples = 0; - void *pci_addr_reg; +#ifdef __BIG_ENDIAN + bits = BIGEND_DMA0 | BIGEND_DMA1; +#else + bits = 0; +#endif + writel(bits, devpriv->plx9080_mmio + PLX_BIGEND_REG); - if (channel) - pci_addr_reg = - priv(dev)->plx9080_iobase + PLX_DMA1_PCI_ADDRESS_REG; - else - pci_addr_reg = - priv(dev)->plx9080_iobase + PLX_DMA0_PCI_ADDRESS_REG; - - /* loop until we have read all the full buffers */ - j = 0; - for (next_transfer_addr = readl(pci_addr_reg); - (next_transfer_addr < - le32_to_cpu(priv(dev)->dma_desc[priv(dev)->dma_desc_index]. - pci_start_addr) - || next_transfer_addr >= - le32_to_cpu(priv(dev)->dma_desc[priv(dev)->dma_desc_index]. - pci_start_addr) + priv(dev)->block_size) - && j < priv(dev)->num_dma_descriptors; j++) { - /* transfer data from dma buffer to comedi buffer */ - num_samples = priv(dev)->block_size / sizeof(uint32_t); - if (async->cmd.stop_src == TRIG_COUNT) { - if (num_samples > priv(dev)->dio_count) - num_samples = priv(dev)->dio_count; - priv(dev)->dio_count -= num_samples; - } - cfc_write_array_to_buffer(dev->read_subdev, - priv(dev)->desc_dio_buffer[priv(dev)-> - dma_desc_index], - num_samples * sizeof(uint32_t)); - priv(dev)->dma_desc_index++; - priv(dev)->dma_desc_index %= priv(dev)->num_dma_descriptors; - - DEBUG_PRINT("next desc addr 0x%lx\n", (unsigned long) - priv(dev)->dma_desc[priv(dev)->dma_desc_index]. - next); - DEBUG_PRINT("pci addr reg 0x%x\n", next_transfer_addr); - } - /* XXX check for buffer overrun somehow */ + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); + + gsc_hpdi_abort_dma(dev, 0); + gsc_hpdi_abort_dma(dev, 1); + + /* configure dma0 mode */ + bits = 0; + /* enable ready input */ + bits |= PLX_DMA_EN_READYIN_BIT; + /* enable dma chaining */ + bits |= PLX_EN_CHAIN_BIT; + /* enable interrupt on dma done + * (probably don't need this, since chain never finishes) */ + bits |= PLX_EN_DMA_DONE_INTR_BIT; + /* don't increment local address during transfers + * (we are transferring from a fixed fifo register) */ + bits |= PLX_LOCAL_ADDR_CONST_BIT; + /* route dma interrupt to pci bus */ + bits |= PLX_DMA_INTR_PCI_BIT; + /* enable demand mode */ + bits |= PLX_DEMAND_MODE_BIT; + /* enable local burst mode */ + bits |= PLX_DMA_LOCAL_BURST_EN_BIT; + bits |= PLX_LOCAL_BUS_32_WIDE_BITS; + writel(bits, plx_iobase + PLX_DMA0_MODE_REG); } -static irqreturn_t handle_interrupt(int irq, void *d) +static const struct hpdi_board *gsc_hpdi_find_board(struct pci_dev *pcidev) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - uint32_t hpdi_intr_status, hpdi_board_status; - uint32_t plx_status; - uint32_t plx_bits; - uint8_t dma0_status, dma1_status; - unsigned long flags; + unsigned int i; - if (!dev->attached) - return IRQ_NONE; + for (i = 0; i < ARRAY_SIZE(hpdi_boards); i++) + if (pcidev->device == hpdi_boards[i].device_id && + pcidev->subsystem_device == hpdi_boards[i].subdevice_id) + return &hpdi_boards[i]; + return NULL; +} - plx_status = readl(priv(dev)->plx9080_iobase + PLX_INTRCS_REG); - if ((plx_status & (ICS_DMA0_A | ICS_DMA1_A | ICS_LIA)) == 0) - return IRQ_NONE; +static int gsc_hpdi_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct hpdi_board *thisboard; + struct hpdi_private *devpriv; + struct comedi_subdevice *s; + int i; + int retval; - hpdi_intr_status = readl(priv(dev)->hpdi_iobase + INTERRUPT_STATUS_REG); - hpdi_board_status = readl(priv(dev)->hpdi_iobase + BOARD_STATUS_REG); + thisboard = gsc_hpdi_find_board(pcidev); + if (!thisboard) { + dev_err(dev->class_dev, "gsc_hpdi: pci %s not supported\n", + pci_name(pcidev)); + return -EINVAL; + } + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; - async->events = 0; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - if (hpdi_intr_status) { - DEBUG_PRINT("hpdi: intr status 0x%x, ", hpdi_intr_status); - writel(hpdi_intr_status, - priv(dev)->hpdi_iobase + INTERRUPT_STATUS_REG); - } - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma0_status = readb(priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); - if (plx_status & ICS_DMA0_A) { /* dma chan 0 interrupt */ - writeb((dma0_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - priv(dev)->plx9080_iobase + PLX_DMA0_CS_REG); + retval = comedi_pci_enable(dev); + if (retval) + return retval; + pci_set_master(pcidev); - DEBUG_PRINT("dma0 status 0x%x\n", dma0_status); - if (dma0_status & PLX_DMA_EN_BIT) - drain_dma_buffers(dev, 0); - DEBUG_PRINT(" cleared dma ch0 interrupt\n"); + devpriv->plx9080_mmio = pci_ioremap_bar(pcidev, 0); + devpriv->mmio = pci_ioremap_bar(pcidev, 2); + if (!devpriv->plx9080_mmio || !devpriv->mmio) { + dev_warn(dev->class_dev, "failed to remap io memory\n"); + return -ENOMEM; } - spin_unlock_irqrestore(&dev->spinlock, flags); - /* spin lock makes sure no one else changes plx dma control reg */ - spin_lock_irqsave(&dev->spinlock, flags); - dma1_status = readb(priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); - if (plx_status & ICS_DMA1_A) { /* XXX *//* dma chan 1 interrupt */ - writeb((dma1_status & PLX_DMA_EN_BIT) | PLX_CLEAR_DMA_INTR_BIT, - priv(dev)->plx9080_iobase + PLX_DMA1_CS_REG); - DEBUG_PRINT("dma1 status 0x%x\n", dma1_status); + gsc_hpdi_init_plx9080(dev); - DEBUG_PRINT(" cleared dma ch1 interrupt\n"); + /* get irq */ + if (request_irq(pcidev->irq, gsc_hpdi_interrupt, IRQF_SHARED, + dev->board_name, dev)) { + dev_warn(dev->class_dev, + "unable to allocate irq %u\n", pcidev->irq); + return -EINVAL; } - spin_unlock_irqrestore(&dev->spinlock, flags); + dev->irq = pcidev->irq; - /* clear possible plx9080 interrupt sources */ - if (plx_status & ICS_LDIA) { /* clear local doorbell interrupt */ - plx_bits = readl(priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG); - writel(plx_bits, priv(dev)->plx9080_iobase + PLX_DBR_OUT_REG); - DEBUG_PRINT(" cleared local doorbell bits 0x%x\n", plx_bits); - } + dev_dbg(dev->class_dev, " irq %u\n", dev->irq); - if (hpdi_board_status & RX_OVERRUN_BIT) { - comedi_error(dev, "rx fifo overrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - DEBUG_PRINT("dma0_status 0x%x\n", - (int)readb(priv(dev)->plx9080_iobase + - PLX_DMA0_CS_REG)); + /* allocate pci dma buffers */ + for (i = 0; i < NUM_DMA_BUFFERS; i++) { + devpriv->dio_buffer[i] = + pci_alloc_consistent(pcidev, DMA_BUFFER_SIZE, + &devpriv->dio_buffer_phys_addr[i]); } - - if (hpdi_board_status & RX_UNDERRUN_BIT) { - comedi_error(dev, "rx fifo underrun"); - async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + /* allocate dma descriptors */ + devpriv->dma_desc = pci_alloc_consistent(pcidev, + sizeof(struct plx_dma_desc) * + NUM_DMA_DESCRIPTORS, + &devpriv->dma_desc_phys_addr); + if (devpriv->dma_desc_phys_addr & 0xf) { + dev_warn(dev->class_dev, + " dma descriptors not quad-word aligned (bug)\n"); + return -EIO; } - if (priv(dev)->dio_count == 0) - async->events |= COMEDI_CB_EOA; + retval = gsc_hpdi_setup_dma_descriptors(dev, 0x1000); + if (retval < 0) + return retval; - DEBUG_PRINT("board status 0x%x, ", hpdi_board_status); - DEBUG_PRINT("plx status 0x%x\n", plx_status); - if (async->events) - DEBUG_PRINT(" events 0x%x\n", async->events); + retval = comedi_alloc_subdevices(dev, 1); + if (retval) + return retval; - cfc_handle_events(dev, s); + /* Digital I/O subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE | SDF_LSAMPL | + SDF_CMD_READ; + s->n_chan = 32; + s->len_chanlist = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = gsc_hpdi_dio_insn_config; + s->do_cmd = gsc_hpdi_cmd; + s->do_cmdtest = gsc_hpdi_cmd_test; + s->cancel = gsc_hpdi_cancel; - return IRQ_HANDLED; + return gsc_hpdi_init(dev); } -static void abort_dma(struct comedi_device *dev, unsigned int channel) +static void gsc_hpdi_detach(struct comedi_device *dev) { - unsigned long flags; - - /* spinlock for plx dma control/status reg */ - spin_lock_irqsave(&dev->spinlock, flags); - - plx9080_abort_dma(priv(dev)->plx9080_iobase, channel); + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct hpdi_private *devpriv = dev->private; + unsigned int i; - spin_unlock_irqrestore(&dev->spinlock, flags); + if (dev->irq) + free_irq(dev->irq, dev); + if (devpriv) { + if (devpriv->plx9080_mmio) { + writel(0, devpriv->plx9080_mmio + PLX_INTRCS_REG); + iounmap(devpriv->plx9080_mmio); + } + if (devpriv->mmio) + iounmap(devpriv->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); } -static int hpdi_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - hpdi_writel(dev, 0, BOARD_CONTROL_REG); +static struct comedi_driver gsc_hpdi_driver = { + .driver_name = "gsc_hpdi", + .module = THIS_MODULE, + .auto_attach = gsc_hpdi_auto_attach, + .detach = gsc_hpdi_detach, +}; - writel(0, priv(dev)->hpdi_iobase + INTERRUPT_CONTROL_REG); +static int gsc_hpdi_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &gsc_hpdi_driver, id->driver_data); +} - abort_dma(dev, 0); +static const struct pci_device_id gsc_hpdi_pci_table[] = { + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9080, PCI_VENDOR_ID_PLX, + 0x2400, 0, 0, 0}, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, gsc_hpdi_pci_table); - return 0; -} +static struct pci_driver gsc_hpdi_pci_driver = { + .name = "gsc_hpdi", + .id_table = gsc_hpdi_pci_table, + .probe = gsc_hpdi_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(gsc_hpdi_driver, gsc_hpdi_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index 126550f3c02..0b8b2162b76 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -13,11 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* @@ -44,28 +39,17 @@ There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V 4 x 16-bit counters -Options: - [0] - PCI bus number - if bus number and slot number are 0, - then driver search for first unused card - [1] - PCI slot number +Configuration options: not applicable, uses PCI auto config */ -#include <linux/interrupt.h> -#include "../comedidev.h" - -#include <linux/delay.h> +#include <linux/module.h> #include <linux/pci.h> +#include <linux/delay.h> +#include <linux/interrupt.h> -#include "icp_multi.h" - -#define DEVICE_ID 0x8000 /* Device ID */ - -#define ICP_MULTI_EXTDEBUG - -/* Hardware types of the cards */ -#define TYPE_ICP_MULTI 0 +#include "../comedidev.h" -#define IORANGE_ICP_MULTI 32 +#define PCI_DEVICE_ID_ICP_MULTI 0x8000 #define ICP_MULTI_ADC_CSR 0 /* R/W: ADC command/status register */ #define ICP_MULTI_AI 2 /* R: Analogue input data */ @@ -80,8 +64,6 @@ Options: #define ICP_MULTI_CNTR2 0x14 /* R/W: Counter 2 */ #define ICP_MULTI_CNTR3 0x16 /* R/W: Counter 3 */ -#define ICP_MULTI_SIZE 0x20 /* 32 bytes */ - /* Define bits from ADC command/status register */ #define ADC_ST 0x0001 /* Start ADC */ #define ADC_BSY 0x0001 /* ADC busy */ @@ -109,166 +91,108 @@ Options: #define Status_IRQ 0x00ff /* All interrupts */ /* Define analogue range */ -static const struct comedi_lrange range_analog = { 4, { - UNI_RANGE(5), - UNI_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(10) - } +static const struct comedi_lrange range_analog = { + 4, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10) + } }; static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; /* ============================================================================== - Forward declarations -============================================================================== -*/ -static int icp_multi_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int icp_multi_detach(struct comedi_device *dev); - -/* -============================================================================== Data & Structure declarations ============================================================================== */ -static unsigned short pci_list_builded; /*>0 list of card is known */ - -struct boardtype { - const char *name; /* driver name */ - int device_id; - int iorange; /* I/O range len */ - char have_irq; /* 1=card support IRQ */ - char cardtype; /* 0=ICP Multi */ - int n_aichan; /* num of A/D chans */ - int n_aichand; /* num of A/D chans in diff mode */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - int n_ctrs; /* num of counters */ - 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 char *rangecode; /* range codes for programming */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ -}; - -static const struct boardtype boardtypes[] = { - {"icp_multi", /* Driver name */ - DEVICE_ID, /* PCI device ID */ - IORANGE_ICP_MULTI, /* I/O range length */ - 1, /* 1=Card supports interrupts */ - TYPE_ICP_MULTI, /* Card type = ICP MULTI */ - 16, /* Num of A/D channels */ - 8, /* Num of A/D channels in diff mode */ - 4, /* Num of D/A channels */ - 16, /* Num of digital inputs */ - 8, /* Num of digital outputs */ - 4, /* Num of counters */ - 0x0fff, /* Resolution of A/D */ - 0x0fff, /* Resolution of D/A */ - &range_analog, /* Rangelist for A/D */ - range_codes_analog, /* Range codes for programming */ - &range_analog}, /* Rangelist for D/A */ -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct boardtype)) - -static struct comedi_driver driver_icp_multi = { - .driver_name = "icp_multi", - .module = THIS_MODULE, - .attach = icp_multi_attach, - .detach = icp_multi_detach, - .num_names = n_boardtypes, - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), -}; - -static int __init driver_icp_multi_init_module(void) -{ - return comedi_driver_register(&driver_icp_multi); -} - -static void __exit driver_icp_multi_cleanup_module(void) -{ - comedi_driver_unregister(&driver_icp_multi); -} - -module_init(driver_icp_multi_init_module); -module_exit(driver_icp_multi_cleanup_module); struct icp_multi_private { - struct pcilst_struct *card; /* pointer to card */ char valid; /* card is usable */ - void *io_addr; /* Pointer to mapped io address */ - resource_size_t phys_iobase; /* Physical io address */ + void __iomem *io_addr; /* Pointer to mapped io address */ unsigned int AdcCmdStatus; /* ADC Command/Status register */ unsigned int DacCmdStatus; /* DAC Command/Status register */ unsigned int IntEnable; /* Interrupt Enable register */ unsigned int IntStatus; /* Interrupt Status register */ - unsigned int act_chanlist[32]; /* list of scaned channel */ + unsigned int act_chanlist[32]; /* list of scanned channel */ unsigned char act_chanlist_len; /* len of scanlist */ unsigned char act_chanlist_pos; /* actual position in MUX list */ unsigned int *ai_chanlist; /* actaul chanlist */ - short *ai_data; /* data buffer */ - short ao_data[4]; /* data output buffer */ - short di_data; /* Digital input data */ + unsigned short ao_data[4]; /* data output buffer */ unsigned int do_data; /* Remember digital output data */ }; -#define devpriv ((struct icp_multi_private *)dev->private) -#define this_board ((const struct boardtype *)dev->board_ptr) - -/* -============================================================================== - More forward declarations -============================================================================== -*/ - -#if 0 -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); -#endif static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); -static int icp_multi_reset(struct comedi_device *dev); + unsigned int *chanlist, unsigned int n_chan) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int i, range, chanprog; + unsigned int diff; -/* -============================================================================== - Functions -============================================================================== -*/ + devpriv->act_chanlist_len = n_chan; + devpriv->act_chanlist_pos = 0; -/* -============================================================================== + for (i = 0; i < n_chan; i++) { + /* Get channel */ + chanprog = CR_CHAN(chanlist[i]); -Name: icp_multi_insn_read_ai + /* Determine if it is a differential channel (Bit 15 = 1) */ + if (CR_AREF(chanlist[i]) == AREF_DIFF) { + diff = 1; + chanprog &= 0x0007; + } else { + diff = 0; + chanprog &= 0x000f; + } -Description: - This function reads a single analogue input. + /* Clear channel, range and input mode bits + * in A/D command/status register */ + devpriv->AdcCmdStatus &= 0xf00f; -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue input data + /* Set channel number and differential mode status bit */ + if (diff) { + /* Set channel number, bits 9-11 & mode, bit 6 */ + devpriv->AdcCmdStatus |= (chanprog << 9); + devpriv->AdcCmdStatus |= ADC_DI; + } else + /* Set channel number, bits 8-11 */ + devpriv->AdcCmdStatus |= (chanprog << 8); -Returns:int Nmuber of instructions executed + /* Get range for current channel */ + range = range_codes_analog[CR_RANGE(chanlist[i])]; + /* Set range. bits 4-5 */ + devpriv->AdcCmdStatus |= range; + + /* Output channel, range, mode to ICP Multi */ + writew(devpriv->AdcCmdStatus, + devpriv->io_addr + ICP_MULTI_ADC_CSR); + } +} + +static int icp_multi_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; + + status = readw(devpriv->io_addr + ICP_MULTI_ADC_CSR); + if ((status & ADC_BSY) == 0) + return 0; + return -EBUSY; +} -============================================================================== -*/ static int icp_multi_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, timeout; + struct icp_multi_private *devpriv = dev->private; + int ret = 0; + int n; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi EDBG: BGN: icp_multi_insn_read_ai(...)\n"); -#endif /* Disable A/D conversion ready interrupt */ devpriv->IntEnable &= ~ADC_READY; writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); @@ -280,12 +204,6 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, /* Set up appropriate channel, mode and range data, for specified ch */ setup_channel_list(dev, s, &insn->chanspec, 1); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp_multi A ST=%4x IO=%p\n", - readw(devpriv->io_addr + ICP_MULTI_ADC_CSR), - devpriv->io_addr + ICP_MULTI_ADC_CSR); -#endif - for (n = 0; n < insn->n; n++) { /* Set start ADC bit */ devpriv->AdcCmdStatus |= ADC_ST; @@ -293,60 +211,13 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, devpriv->io_addr + ICP_MULTI_ADC_CSR); devpriv->AdcCmdStatus &= ~ADC_ST; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi B n=%d ST=%4x\n", n, - readw(devpriv->io_addr + ICP_MULTI_ADC_CSR)); -#endif - udelay(1); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi C n=%d ST=%4x\n", n, - readw(devpriv->io_addr + ICP_MULTI_ADC_CSR)); -#endif - /* Wait for conversion to complete, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_ADC_CSR) & ADC_BSY)) - goto conv_finish; - -#ifdef ICP_MULTI_EXTDEBUG - if (!(timeout % 10)) - printk(KERN_DEBUG - "icp multi D n=%d tm=%d ST=%4x\n", n, - timeout, - readw(devpriv->io_addr + - ICP_MULTI_ADC_CSR)); -#endif - - udelay(1); - } - - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "A/D insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~ADC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= ADC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); + ret = comedi_timeout(dev, s, insn, icp_multi_ai_eoc, 0); + if (ret) + break; - /* Clear data received */ - data[n] = 0; - -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n", - n); -#endif - return -ETIME; - -conv_finish: data[n] = (readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff; } @@ -359,41 +230,31 @@ conv_finish: devpriv->IntStatus |= ADC_READY; writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n", n); -#endif - return n; + return ret ? ret : n; } -/* -============================================================================== - -Name: icp_multi_insn_write_ao - -Description: - This function writes a single analogue output. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue output data +static int icp_multi_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct icp_multi_private *devpriv = dev->private; + unsigned int status; -Returns:int Nmuber of instructions executed + status = readw(devpriv->io_addr + ICP_MULTI_DAC_CSR); + if ((status & DAC_BSY) == 0) + return 0; + return -EBUSY; +} -============================================================================== -*/ static int icp_multi_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, chan, range, timeout; + struct icp_multi_private *devpriv = dev->private; + int n, chan, range; + int ret; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: BGN: icp_multi_insn_write_ao(...)\n"); -#endif /* Disable D/A conversion ready interrupt */ devpriv->IntEnable &= ~DAC_READY; writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); @@ -412,7 +273,7 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, /* Bit 5 = 1 : 10V */ /* Bits 8-9 : Channel number */ devpriv->DacCmdStatus &= 0xfccf; - devpriv->DacCmdStatus |= this_board->rangecode[range]; + devpriv->DacCmdStatus |= range_codes_analog[range]; devpriv->DacCmdStatus |= (chan << 8); writew(devpriv->DacCmdStatus, devpriv->io_addr + ICP_MULTI_DAC_CSR); @@ -420,47 +281,24 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { /* Wait for analogue output data register to be * ready for new data, or get fed up waiting */ - timeout = 100; - while (timeout--) { - if (!(readw(devpriv->io_addr + - ICP_MULTI_DAC_CSR) & DAC_BSY)) - goto dac_ready; - -#ifdef ICP_MULTI_EXTDEBUG - if (!(timeout % 10)) - printk(KERN_DEBUG - "icp multi A n=%d tm=%d ST=%4x\n", n, - timeout, - readw(devpriv->io_addr + - ICP_MULTI_DAC_CSR)); -#endif - - udelay(1); + ret = comedi_timeout(dev, s, insn, icp_multi_ao_eoc, 0); + if (ret) { + /* Disable interrupt */ + devpriv->IntEnable &= ~DAC_READY; + writew(devpriv->IntEnable, + devpriv->io_addr + ICP_MULTI_INT_EN); + + /* Clear interrupt status */ + devpriv->IntStatus |= DAC_READY; + writew(devpriv->IntStatus, + devpriv->io_addr + ICP_MULTI_INT_STAT); + + /* Clear data received */ + devpriv->ao_data[chan] = 0; + + return ret; } - /* If we reach here, a timeout has occurred */ - comedi_error(dev, "D/A insn timeout"); - - /* Disable interrupt */ - devpriv->IntEnable &= ~DAC_READY; - writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); - - /* Clear interrupt status */ - devpriv->IntStatus |= DAC_READY; - writew(devpriv->IntStatus, - devpriv->io_addr + ICP_MULTI_INT_STAT); - - /* Clear data received */ - devpriv->ao_data[chan] = 0; - -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n", - n); -#endif - return -ETIME; - -dac_ready: /* Write data to analogue output data register */ writew(data[n], devpriv->io_addr + ICP_MULTI_AO); @@ -474,35 +312,14 @@ dac_ready: devpriv->ao_data[chan] = data[n]; } -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n", n); -#endif return n; } -/* -============================================================================== - -Name: icp_multi_insn_read_ao - -Description: - This function reads a single analogue output. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue output data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ 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 */ @@ -515,94 +332,32 @@ static int icp_multi_insn_read_ao(struct comedi_device *dev, return n; } -/* -============================================================================== - -Name: icp_multi_insn_bits_di - -Description: - This function reads the digital inputs. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue output data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_bits_di(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct icp_multi_private *devpriv = dev->private; + data[1] = readw(devpriv->io_addr + ICP_MULTI_DI); - return 2; + return insn->n; } -/* -============================================================================== - -Name: icp_multi_insn_bits_do - -Description: - This function writes the appropriate digital outputs. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue output data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi EDBG: BGN: icp_multi_insn_bits_do(...)\n"); -#endif - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - printk(KERN_DEBUG "Digital outputs = %4x \n", s->state); + struct icp_multi_private *devpriv = dev->private; + if (comedi_dio_update_state(s, data)) writew(s->state, devpriv->io_addr + ICP_MULTI_DO); - } data[1] = readw(devpriv->io_addr + ICP_MULTI_DI); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_insn_bits_do(...)\n"); -#endif - return 2; + return insn->n; } -/* -============================================================================== - -Name: icp_multi_insn_read_ctr - -Description: - This function reads the specified counter. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to counter data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_read_ctr(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -610,24 +365,6 @@ static int icp_multi_insn_read_ctr(struct comedi_device *dev, return 0; } -/* -============================================================================== - -Name: icp_multi_insn_write_ctr - -Description: - This function write to the specified counter. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to counter data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_write_ctr(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -636,44 +373,18 @@ static int icp_multi_insn_write_ctr(struct comedi_device *dev, return 0; } -/* -============================================================================== - -Name: interrupt_service_icp_multi - -Description: - This function is the interrupt service routine for all - interrupts generated by the icp multi board. - -Parameters: - int irq - void *d Pointer to current device - -============================================================================== -*/ static irqreturn_t interrupt_service_icp_multi(int irq, void *d) { struct comedi_device *dev = d; + struct icp_multi_private *devpriv = dev->private; int int_no; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: BGN: interrupt_service_icp_multi(%d,...)\n", - irq); -#endif - /* Is this interrupt from our board? */ int_no = readw(devpriv->io_addr + ICP_MULTI_INT_STAT) & Status_IRQ; if (!int_no) /* No, exit */ return IRQ_NONE; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: interrupt_service_icp_multi() ST: %4x\n", - readw(devpriv->io_addr + ICP_MULTI_INT_STAT)); -#endif - /* Determine which interrupt is active & handle it */ switch (int_no) { case ADC_READY: @@ -697,44 +408,16 @@ static irqreturn_t interrupt_service_icp_multi(int irq, void *d) } -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: interrupt_service_icp_multi(...)\n"); -#endif return IRQ_HANDLED; } #if 0 -/* -============================================================================== - -Name: check_channel_list - -Description: - This function checks if the channel list, provided by user - is built correctly - -Parameters: - struct comedi_device *dev Pointer to current service structure - struct comedi_subdevice *s Pointer to current subdevice structure - unsigned int *chanlist Pointer to packed channel list - unsigned int n_chan Number of channels to scan - -Returns:int 0 = failure - 1 = success - -============================================================================== -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) { unsigned int i; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: check_channel_list(...,%d)\n", n_chan); -#endif /* Check that we at least have one channel to check */ if (n_chan < 1) { comedi_error(dev, "range/channel list is empty!"); @@ -744,13 +427,13 @@ static int check_channel_list(struct comedi_device *dev, for (i = 0; i < n_chan; i++) { /* Check that channel number is < maximum */ if (CR_AREF(chanlist[i]) == AREF_DIFF) { - if (CR_CHAN(chanlist[i]) > this_board->n_aichand) { + if (CR_CHAN(chanlist[i]) > (s->nchan / 2)) { comedi_error(dev, "Incorrect differential ai ch-nr"); return 0; } } else { - if (CR_CHAN(chanlist[i]) > this_board->n_aichan) { + if (CR_CHAN(chanlist[i]) > s->n_chan) { comedi_error(dev, "Incorrect ai channel number"); return 0; @@ -761,382 +444,169 @@ static int check_channel_list(struct comedi_device *dev, } #endif -/* -============================================================================== - -Name: setup_channel_list - -Description: - This function sets the appropriate channel selection, - differential input mode and range bits in the ADC Command/ - Status register. - -Parameters: - struct comedi_device *dev Pointer to current service structure - struct comedi_subdevice *s Pointer to current subdevice structure - unsigned int *chanlist Pointer to packed channel list - unsigned int n_chan Number of channels to scan - -Returns:Void - -============================================================================== -*/ -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) -{ - unsigned int i, range, chanprog; - unsigned int diff; - -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan); -#endif - devpriv->act_chanlist_len = n_chan; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < n_chan; i++) { - /* Get channel */ - chanprog = CR_CHAN(chanlist[i]); - - /* Determine if it is a differential channel (Bit 15 = 1) */ - if (CR_AREF(chanlist[i]) == AREF_DIFF) { - diff = 1; - chanprog &= 0x0007; - } else { - diff = 0; - chanprog &= 0x000f; - } - - /* Clear channel, range and input mode bits - * in A/D command/status register */ - devpriv->AdcCmdStatus &= 0xf00f; - - /* Set channel number and differential mode status bit */ - if (diff) { - /* Set channel number, bits 9-11 & mode, bit 6 */ - devpriv->AdcCmdStatus |= (chanprog << 9); - devpriv->AdcCmdStatus |= ADC_DI; - } else - /* Set channel number, bits 8-11 */ - devpriv->AdcCmdStatus |= (chanprog << 8); - - /* Get range for current channel */ - range = this_board->rangecode[CR_RANGE(chanlist[i])]; - /* Set range. bits 4-5 */ - devpriv->AdcCmdStatus |= range; - - /* Output channel, range, mode to ICP Multi */ - writew(devpriv->AdcCmdStatus, - devpriv->io_addr + ICP_MULTI_ADC_CSR); - -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, - devpriv->act_chanlist[i]); -#endif - } - -} - -/* -============================================================================== - -Name: icp_multi_reset - -Description: - This function resets the icp multi device to a 'safe' state - -Parameters: - struct comedi_device *dev Pointer to current service structure - -Returns:int 0 = success - -============================================================================== -*/ static int icp_multi_reset(struct comedi_device *dev) { + struct icp_multi_private *devpriv = dev->private; unsigned int i; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp_multi EDBG: BGN: icp_multi_reset(...)\n"); -#endif /* Clear INT enables and requests */ writew(0, devpriv->io_addr + ICP_MULTI_INT_EN); writew(0x00ff, devpriv->io_addr + ICP_MULTI_INT_STAT); - if (this_board->n_aochan) - /* Set DACs to 0..5V range and 0V output */ - for (i = 0; i < this_board->n_aochan; i++) { - devpriv->DacCmdStatus &= 0xfcce; + /* Set DACs to 0..5V range and 0V output */ + for (i = 0; i < 4; i++) { + devpriv->DacCmdStatus &= 0xfcce; - /* Set channel number */ - devpriv->DacCmdStatus |= (i << 8); + /* Set channel number */ + devpriv->DacCmdStatus |= (i << 8); - /* Output 0V */ - writew(0, devpriv->io_addr + ICP_MULTI_AO); + /* Output 0V */ + writew(0, devpriv->io_addr + ICP_MULTI_AO); - /* Set start conversion bit */ - devpriv->DacCmdStatus |= DAC_ST; + /* Set start conversion bit */ + devpriv->DacCmdStatus |= DAC_ST; - /* Output to command / status register */ - writew(devpriv->DacCmdStatus, - devpriv->io_addr + ICP_MULTI_DAC_CSR); + /* Output to command / status register */ + writew(devpriv->DacCmdStatus, + devpriv->io_addr + ICP_MULTI_DAC_CSR); - /* Delay to allow DAC time to recover */ - udelay(1); - } - /* Digital outputs to 0 */ + /* Delay to allow DAC time to recover */ + udelay(1); + } + + /* Digital outputs to 0 */ writew(0, devpriv->io_addr + ICP_MULTI_DO); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_reset(...)\n"); -#endif return 0; } -/* -============================================================================== - -Name: icp_multi_attach - -Description: - This function sets up all the appropriate data for the current - device. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_devconfig *it Pointer to current device configuration - -Returns:int 0 = success - -============================================================================== -*/ -static int icp_multi_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int icp_multi_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct icp_multi_private *devpriv; struct comedi_subdevice *s; - int ret, subdev, n_subdevices; - unsigned int irq; - struct pcilst_struct *card = NULL; - resource_size_t io_addr[5], iobase; - unsigned char pci_bus, pci_slot, pci_func; - - printk(KERN_WARNING - "icp_multi EDBG: BGN: icp_multi_attach(...)\n"); - - /* Alocate private data storage space */ - ret = alloc_private(dev, sizeof(struct icp_multi_private)); - if (ret < 0) - return ret; - - /* Initialise list of PCI cards in system, if not already done so */ - if (pci_list_builded++ == 0) { - pci_card_list_init(PCI_VENDOR_ID_ICP, -#ifdef ICP_MULTI_EXTDEBUG - 1 -#else - 0 -#endif - ); - } + int ret; - printk(KERN_WARNING - "Anne's comedi%d: icp_multi: board=%s", dev->minor, - this_board->name); - - card = select_and_alloc_pci_card(PCI_VENDOR_ID_ICP, - this_board->device_id, it->options[0], - it->options[1]); - - if (card == NULL) - return -EIO; - - devpriv->card = card; - - if ((pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0], - &irq)) < 0) { - printk(KERN_WARNING " - Can't get configuration data!\n"); - return -EIO; - } - - iobase = io_addr[2]; - devpriv->phys_iobase = iobase; - - printk(KERN_WARNING - ", b:s:f=%d:%d:%d, io=0x%8llx \n", pci_bus, pci_slot, pci_func, - (unsigned long long)iobase); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE); + ret = comedi_pci_enable(dev); + if (ret) + return ret; - if (devpriv->io_addr == NULL) { - printk(KERN_WARNING "ioremap failed.\n"); + devpriv->io_addr = pci_ioremap_bar(pcidev, 2); + if (!devpriv->io_addr) return -ENOMEM; - } -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "0x%08llx mapped to %p, ", (unsigned long long)iobase, - devpriv->io_addr); -#endif - dev->board_name = this_board->name; - - n_subdevices = 0; - if (this_board->n_aichan) - n_subdevices++; - if (this_board->n_aochan) - n_subdevices++; - if (this_board->n_dichan) - n_subdevices++; - if (this_board->n_dochan) - n_subdevices++; - if (this_board->n_ctrs) - n_subdevices++; - - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 5); + if (ret) return ret; icp_multi_reset(dev); - if (this_board->have_irq) { - if (irq) { - if (request_irq(irq, interrupt_service_icp_multi, - IRQF_SHARED, "Inova Icp Multi", dev)) { - printk(KERN_WARNING - "unable to allocate IRQ %u, DISABLING IT", - irq); - irq = 0; /* Can't use IRQ */ - } else - printk(KERN_WARNING ", irq=%u", irq); - } else - printk(KERN_WARNING ", IRQ disabled"); - } else - irq = 0; - - dev->irq = irq; - - printk(KERN_WARNING ".\n"); - - subdev = 0; - - if (this_board->n_aichan) { - s = dev->subdevices + subdev; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; - if (this_board->n_aichand) - s->subdev_flags |= SDF_DIFF; - s->n_chan = this_board->n_aichan; - s->maxdata = this_board->ai_maxdata; - s->len_chanlist = this_board->n_aichan; - s->range_table = this_board->rangelist_ai; - s->insn_read = icp_multi_insn_read_ai; - subdev++; - } - - if (this_board->n_aochan) { - s = dev->subdevices + subdev; - 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 = icp_multi_insn_write_ao; - s->insn_read = icp_multi_insn_read_ao; - subdev++; - } - - if (this_board->n_dichan) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = this_board->n_dichan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dichan; - s->range_table = &range_digital; - s->io_bits = 0; - s->insn_bits = icp_multi_insn_bits_di; - subdev++; + if (pcidev->irq) { + ret = request_irq(pcidev->irq, interrupt_service_icp_multi, + IRQF_SHARED, dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; } - if (this_board->n_dochan) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = this_board->n_dochan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dochan; - s->range_table = &range_digital; - s->io_bits = (1 << this_board->n_dochan) - 1; - s->state = 0; - s->insn_bits = icp_multi_insn_bits_do; - subdev++; - } - - if (this_board->n_ctrs) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_ctrs; - s->maxdata = 0xffff; - s->len_chanlist = this_board->n_ctrs; - s->state = 0; - s->insn_read = icp_multi_insn_read_ctr; - s->insn_write = icp_multi_insn_write_ctr; - subdev++; - } + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->len_chanlist = 16; + s->range_table = &range_analog; + s->insn_read = icp_multi_insn_read_ai; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 4; + s->maxdata = 0x0fff; + s->len_chanlist = 4; + s->range_table = &range_analog; + s->insn_write = icp_multi_insn_write_ao; + s->insn_read = icp_multi_insn_read_ao; + + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->len_chanlist = 16; + s->range_table = &range_digital; + s->insn_bits = icp_multi_insn_bits_di; + + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->len_chanlist = 8; + s->range_table = &range_digital; + s->insn_bits = icp_multi_insn_bits_do; + + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + s->state = 0; + s->insn_read = icp_multi_insn_read_ctr; + s->insn_write = icp_multi_insn_write_ctr; devpriv->valid = 1; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_attach(...)\n"); -#endif - return 0; } -/* -============================================================================== - -Name: icp_multi_detach - -Description: - This function releases all the resources used by the current - device. - -Parameters: - struct comedi_device *dev Pointer to current device structure - -Returns:int 0 = success - -============================================================================== -*/ -static int icp_multi_detach(struct comedi_device *dev) +static void icp_multi_detach(struct comedi_device *dev) { + struct icp_multi_private *devpriv = dev->private; - if (dev->private) + if (devpriv) if (devpriv->valid) icp_multi_reset(dev); - if (dev->irq) free_irq(dev->irq, dev); - - if (dev->private && devpriv->io_addr) + if (devpriv && devpriv->io_addr) iounmap(devpriv->io_addr); + comedi_pci_disable(dev); +} - if (dev->private && devpriv->card) - pci_card_free(devpriv->card); - - if (--pci_list_builded == 0) - pci_card_list_cleanup(PCI_VENDOR_ID_ICP); +static struct comedi_driver icp_multi_driver = { + .driver_name = "icp_multi", + .module = THIS_MODULE, + .auto_attach = icp_multi_auto_attach, + .detach = icp_multi_detach, +}; - return 0; +static int icp_multi_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &icp_multi_driver, id->driver_data); } +static const struct pci_device_id icp_multi_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ICP, PCI_DEVICE_ID_ICP_MULTI) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, icp_multi_pci_table); + +static struct pci_driver icp_multi_pci_driver = { + .name = "icp_multi", + .id_table = icp_multi_pci_table, + .probe = icp_multi_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(icp_multi_driver, icp_multi_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/icp_multi.h b/drivers/staging/comedi/drivers/icp_multi.h deleted file mode 100644 index 68acefe1688..00000000000 --- a/drivers/staging/comedi/drivers/icp_multi.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - comedi/drivers/icp_multi.h - - Stuff for ICP Multi - - Author: Anne Smorthit <anne.smorthit@sfwte.ch> - -*/ - -#ifndef _ICP_MULTI_H_ -#define _ICP_MULTI_H_ - -#include "../comedidev.h" -#include "comedi_pci.h" - -/****************************************************************************/ - -struct pcilst_struct { - struct pcilst_struct *next; - int used; - struct pci_dev *pcidev; - unsigned short vendor; - unsigned short device; - unsigned char pci_bus; - unsigned char pci_slot; - unsigned char pci_func; - resource_size_t io_addr[5]; - unsigned int irq; -}; - -struct pcilst_struct *inova_devices; -/* ptr to root list of all Inova devices */ - -/****************************************************************************/ - -static void pci_card_list_init(unsigned short pci_vendor, char display); -static void pci_card_list_cleanup(unsigned short pci_vendor); -static struct pcilst_struct *find_free_pci_card_by_device(unsigned short - vendor_id, - unsigned short - device_id); -static int find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card); -static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot); - -static int pci_card_alloc(struct pcilst_struct *amcc); -static int pci_card_free(struct pcilst_struct *amcc); -static void pci_card_list_display(void); -static int pci_card_data(struct pcilst_struct *amcc, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, resource_size_t * io_addr, - unsigned int *irq); - -/****************************************************************************/ - -/* build list of Inova cards in this system */ -static void pci_card_list_init(unsigned short pci_vendor, char display) -{ - struct pci_dev *pcidev = NULL; - struct pcilst_struct *inova, *last; - int i; - - inova_devices = NULL; - last = NULL; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == pci_vendor) { - inova = kzalloc(sizeof(*inova), GFP_KERNEL); - if (!inova) { - printk - ("icp_multi: pci_card_list_init: allocation failed\n"); - pci_dev_put(pcidev); - break; - } - - inova->pcidev = pci_dev_get(pcidev); - if (last) { - last->next = inova; - } else { - inova_devices = inova; - } - last = inova; - - inova->vendor = pcidev->vendor; - inova->device = pcidev->device; - inova->pci_bus = pcidev->bus->number; - inova->pci_slot = PCI_SLOT(pcidev->devfn); - inova->pci_func = PCI_FUNC(pcidev->devfn); - /* Note: resources may be invalid if PCI device - * not enabled, but they are corrected in - * pci_card_alloc. */ - for (i = 0; i < 5; i++) - inova->io_addr[i] = - pci_resource_start(pcidev, i); - inova->irq = pcidev->irq; - } - } - - if (display) - pci_card_list_display(); -} - -/****************************************************************************/ -/* free up list of amcc cards in this system */ -static void pci_card_list_cleanup(unsigned short pci_vendor) -{ - struct pcilst_struct *inova, *next; - - for (inova = inova_devices; inova; inova = next) { - next = inova->next; - pci_dev_put(inova->pcidev); - kfree(inova); - } - - inova_devices = NULL; -} - -/****************************************************************************/ -/* find first unused card with this device_id */ -static struct pcilst_struct *find_free_pci_card_by_device(unsigned short - vendor_id, - unsigned short - device_id) -{ - struct pcilst_struct *inova, *next; - - for (inova = inova_devices; inova; inova = next) { - next = inova->next; - if ((!inova->used) && (inova->device == device_id) - && (inova->vendor == vendor_id)) - return inova; - - } - - return NULL; -} - -/****************************************************************************/ -/* find card on requested position */ -static int find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card) -{ - struct pcilst_struct *inova, *next; - - *card = NULL; - for (inova = inova_devices; inova; inova = next) { - next = inova->next; - if ((inova->vendor == vendor_id) && (inova->device == device_id) - && (inova->pci_bus == pci_bus) - && (inova->pci_slot == pci_slot)) { - if (!(inova->used)) { - *card = inova; - return 0; /* ok, card is found */ - } else { - return 2; /* card exist but is used */ - } - } - } - - return 1; /* no card found */ -} - -/****************************************************************************/ -/* mark card as used */ -static int pci_card_alloc(struct pcilst_struct *inova) -{ - int i; - - if (!inova) { - printk(" - BUG!! inova is NULL!\n"); - return -1; - } - - if (inova->used) - return 1; - if (comedi_pci_enable(inova->pcidev, "icp_multi")) { - printk(" - Can't enable PCI device and request regions!\n"); - return -1; - } - /* Resources will be accurate now. */ - for (i = 0; i < 5; i++) - inova->io_addr[i] = pci_resource_start(inova->pcidev, i); - inova->irq = inova->pcidev->irq; - inova->used = 1; - return 0; -} - -/****************************************************************************/ -/* mark card as free */ -static int pci_card_free(struct pcilst_struct *inova) -{ - if (!inova) - return -1; - - if (!inova->used) - return 1; - inova->used = 0; - comedi_pci_disable(inova->pcidev); - return 0; -} - -/****************************************************************************/ -/* display list of found cards */ -static void pci_card_list_display(void) -{ - struct pcilst_struct *inova, *next; - - printk("Anne's List of pci cards\n"); - printk("bus:slot:func vendor device io_inova io_daq irq used\n"); - - for (inova = inova_devices; inova; inova = next) { - next = inova->next; - printk - ("%2d %2d %2d 0x%4x 0x%4x 0x%8llx 0x%8llx %2u %2d\n", - inova->pci_bus, inova->pci_slot, inova->pci_func, - inova->vendor, inova->device, - (unsigned long long)inova->io_addr[0], - (unsigned long long)inova->io_addr[2], inova->irq, - inova->used); - - } -} - -/****************************************************************************/ -/* return all card information for driver */ -static int pci_card_data(struct pcilst_struct *inova, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, resource_size_t * io_addr, - unsigned int *irq) -{ - int i; - - if (!inova) - return -1; - *pci_bus = inova->pci_bus; - *pci_slot = inova->pci_slot; - *pci_func = inova->pci_func; - for (i = 0; i < 5; i++) - io_addr[i] = inova->io_addr[i]; - *irq = inova->irq; - return 0; -} - -/****************************************************************************/ -/* select and alloc card */ -static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot) -{ - struct pcilst_struct *card; - int err; - - if ((pci_bus < 1) & (pci_slot < 1)) { /* use autodetection */ - - card = find_free_pci_card_by_device(vendor_id, device_id); - if (card == NULL) { - printk(" - Unused card not found in system!\n"); - return NULL; - } - } else { - switch (find_free_pci_card_by_position(vendor_id, device_id, - pci_bus, pci_slot, - &card)) { - case 1: - printk - (" - Card not found on requested position b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - case 2: - printk - (" - Card on requested position is used b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - } - } - - err = pci_card_alloc(card); - if (err != 0) { - if (err > 0) - printk(" - Can't allocate card!\n"); - /* else: error already printed. */ - return NULL; - } - - return card; -} - -#endif diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index e4711ef5471..2516ce83483 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -1,683 +1,533 @@ /* - * comedi/drivers/ii_pci20kc.c - * Driver for Intelligent Instruments PCI-20001C carrier board - * and modules. + * ii_pci20kc.c + * Driver for Intelligent Instruments PCI-20001C carrier board and modules. * - * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de> - * with suggestions from David Schleef - * 16.06.2000 - * - * Linux device driver for COMEDI - * Intelligent Instrumentation - * PCI-20001 C-2A Carrier Board - * PCI-20341 M-1A 16-Bit analog input module - * - differential - * - range (-5V - +5V) - * - 16 bit - * PCI-20006 M-2 16-Bit analog output module - * - ranges (-10V - +10V) (0V - +10V) (-5V - +5V) - * - 16 bit - * - * only ONE PCI-20341 module possible - * only ONE PCI-20006 module possible - * no extern trigger implemented - * - * NOT WORKING (but soon) only 4 on-board differential channels supported - * NOT WORKING (but soon) only ONE di-port and ONE do-port supported - * instead of 4 digital ports - * di-port == Port 0 - * do-port == Port 1 - * - * The state of this driver is only a starting point for a complete - * COMEDI-driver. The final driver should support all features of the - * carrier board and modules. + * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de> + * with suggestions from David Schleef 16.06.2000 + */ + +/* + * Driver: ii_pci20kc + * Description: Intelligent Instruments PCI-20001C carrier board + * Devices: (Intelligent Instrumentation) PCI-20001C [ii_pci20kc] + * Author: Markus Kempf <kempf@matsci.uni-sb.de> + * Status: works * - * The test configuration: + * Supports the PCI-20001C-1a and PCI-20001C-2a carrier boards. The + * -2a version has 32 on-board DIO channels. Three add-on modules + * can be added to the carrier board for additional functionality. * - * kernel 2.2.14 with RTAI v1.2 and patch-2.2.14rthal2 - * COMEDI 0.7.45 - * COMEDILIB 0.7.9 + * Supported add-on modules: + * PCI-20006M-1 1 channel, 16-bit analog output module + * PCI-20006M-2 2 channel, 16-bit analog output module + * PCI-20341M-1A 4 channel, 16-bit analog input module * + * Options: + * 0 Board base address + * 1 IRQ (not-used) */ -/* -Driver: ii_pci20kc -Description: Intelligent Instruments PCI-20001C carrier board -Author: Markus Kempf <kempf@matsci.uni-sb.de> -Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc) -Status: works - -Supports the PCI-20001 C-2a Carrier board, and could probably support -the other carrier boards with small modifications. Modules supported -are: - PCI-20006 M-2 16-bit analog output module - PCI-20341 M-1A 16-bit analog input module - -Options: - 0 Board base address - 1 IRQ - 2 first option for module 1 - 3 second option for module 1 - 4 first option for module 2 - 5 second option for module 2 - 6 first option for module 3 - 7 second option for module 3 - -options for PCI-20006M: - first: Analog output channel 0 range configuration - 0 bipolar 10 (-10V -- +10V) - 1 unipolar 10 (0V -- +10V) - 2 bipolar 5 (-5V -- 5V) - second: Analog output channel 1 range configuration - -options for PCI-20341M: - first: Analog input gain configuration - 0 1 - 1 10 - 2 100 - 3 200 -*/ - -/* XXX needs to use ioremap() for compatibility with 2.4 kernels. Should also - * check_mem_region() etc. - fmhess */ +#include <linux/module.h> #include "../comedidev.h" -#define PCI20000_ID 0x1d -#define PCI20341_ID 0x77 -#define PCI20006_ID 0xe3 -#define PCI20xxx_EMPTY_ID 0xff - -#define PCI20000_OFFSET 0x100 -#define PCI20000_MODULES 3 - -#define PCI20000_DIO_0 0x80 -#define PCI20000_DIO_1 0x81 -#define PCI20000_DIO_2 0xc0 -#define PCI20000_DIO_3 0xc1 -#define PCI20000_DIO_CONTROL_01 0x83 /* port 0, 1 control */ -#define PCI20000_DIO_CONTROL_23 0xc3 /* port 2, 3 control */ -#define PCI20000_DIO_BUFFER 0x82 /* buffer direction & enable */ -#define PCI20000_DIO_EOC 0xef /* even port, control output */ -#define PCI20000_DIO_OOC 0xfd /* odd port, control output */ -#define PCI20000_DIO_EIC 0x90 /* even port, control input */ -#define PCI20000_DIO_OIC 0x82 /* odd port, control input */ -#define DIO_CAND 0x12 /* and bit 1 & 4 of control */ -#define DIO_BE 0x01 /* buffer: port enable */ -#define DIO_BO 0x04 /* buffer: output */ -#define DIO_BI 0x05 /* buffer: input */ -#define DIO_PS_0 0x00 /* buffer: port shift 0 */ -#define DIO_PS_1 0x01 /* buffer: port shift 1 */ -#define DIO_PS_2 0x04 /* buffer: port shift 2 */ -#define DIO_PS_3 0x05 /* buffer: port shift 3 */ - -#define PCI20006_LCHAN0 0x0d -#define PCI20006_STROBE0 0x0b -#define PCI20006_LCHAN1 0x15 -#define PCI20006_STROBE1 0x13 - -#define PCI20341_INIT 0x04 -#define PCI20341_REPMODE 0x00 /* single shot mode */ -#define PCI20341_PACER 0x00 /* Hardware Pacer disabled */ -#define PCI20341_CHAN_NR 0x04 /* number of input channels */ -#define PCI20341_CONFIG_REG 0x10 -#define PCI20341_MOD_STATUS 0x01 -#define PCI20341_OPT_REG 0x11 -#define PCI20341_SET_TIME_REG 0x15 -#define PCI20341_LCHAN_ADDR_REG 0x13 -#define PCI20341_CHAN_LIST 0x80 -#define PCI20341_CC_RESET 0x1b -#define PCI20341_CHAN_RESET 0x19 -#define PCI20341_SOFT_PACER 0x04 -#define PCI20341_STATUS_REG 0x12 -#define PCI20341_LDATA 0x02 -#define PCI20341_DAISY_CHAIN 0x20 /* On-board inputs only */ -#define PCI20341_MUX 0x04 /* Enable on-board MUX */ -#define PCI20341_SCANLIST 0x80 /* Channel/Gain Scan List */ - -union pci20xxx_subdev_private { - void *iobase; - struct { - void *iobase; - const struct comedi_lrange *ao_range_list[2]; - /* range of channels of ao module */ - unsigned int last_data[2]; - } pci20006; - struct { - void *iobase; - int timebase; - int settling_time; - int ai_gain; - } pci20341; +/* + * Register I/O map + */ +#define II20K_MOD_OFFSET 0x100 +#define II20K_ID_REG 0x00 +#define II20K_ID_MOD1_EMPTY (1 << 7) +#define II20K_ID_MOD2_EMPTY (1 << 6) +#define II20K_ID_MOD3_EMPTY (1 << 5) +#define II20K_ID_MASK 0x1f +#define II20K_ID_PCI20001C_1A 0x1b /* no on-board DIO */ +#define II20K_ID_PCI20001C_2A 0x1d /* on-board DIO */ +#define II20K_MOD_STATUS_REG 0x40 +#define II20K_MOD_STATUS_IRQ_MOD1 (1 << 7) +#define II20K_MOD_STATUS_IRQ_MOD2 (1 << 6) +#define II20K_MOD_STATUS_IRQ_MOD3 (1 << 5) +#define II20K_DIO0_REG 0x80 +#define II20K_DIO1_REG 0x81 +#define II20K_DIR_ENA_REG 0x82 +#define II20K_DIR_DIO3_OUT (1 << 7) +#define II20K_DIR_DIO2_OUT (1 << 6) +#define II20K_BUF_DISAB_DIO3 (1 << 5) +#define II20K_BUF_DISAB_DIO2 (1 << 4) +#define II20K_DIR_DIO1_OUT (1 << 3) +#define II20K_DIR_DIO0_OUT (1 << 2) +#define II20K_BUF_DISAB_DIO1 (1 << 1) +#define II20K_BUF_DISAB_DIO0 (1 << 0) +#define II20K_CTRL01_REG 0x83 +#define II20K_CTRL01_SET (1 << 7) +#define II20K_CTRL01_DIO0_IN (1 << 4) +#define II20K_CTRL01_DIO1_IN (1 << 1) +#define II20K_DIO2_REG 0xc0 +#define II20K_DIO3_REG 0xc1 +#define II20K_CTRL23_REG 0xc3 +#define II20K_CTRL23_SET (1 << 7) +#define II20K_CTRL23_DIO2_IN (1 << 4) +#define II20K_CTRL23_DIO3_IN (1 << 1) + +#define II20K_ID_PCI20006M_1 0xe2 /* 1 AO channels */ +#define II20K_ID_PCI20006M_2 0xe3 /* 2 AO channels */ +#define II20K_AO_STRB_REG(x) (0x0b + ((x) * 0x08)) +#define II20K_AO_LSB_REG(x) (0x0d + ((x) * 0x08)) +#define II20K_AO_MSB_REG(x) (0x0e + ((x) * 0x08)) +#define II20K_AO_STRB_BOTH_REG 0x1b + +#define II20K_ID_PCI20341M_1 0x77 /* 4 AI channels */ +#define II20K_AI_STATUS_CMD_REG 0x01 +#define II20K_AI_STATUS_CMD_BUSY (1 << 7) +#define II20K_AI_STATUS_CMD_HW_ENA (1 << 1) +#define II20K_AI_STATUS_CMD_EXT_START (1 << 0) +#define II20K_AI_LSB_REG 0x02 +#define II20K_AI_MSB_REG 0x03 +#define II20K_AI_PACER_RESET_REG 0x04 +#define II20K_AI_16BIT_DATA_REG 0x06 +#define II20K_AI_CONF_REG 0x10 +#define II20K_AI_CONF_ENA (1 << 2) +#define II20K_AI_OPT_REG 0x11 +#define II20K_AI_OPT_TRIG_ENA (1 << 5) +#define II20K_AI_OPT_TRIG_INV (1 << 4) +#define II20K_AI_OPT_TIMEBASE(x) (((x) & 0x3) << 1) +#define II20K_AI_OPT_BURST_MODE (1 << 0) +#define II20K_AI_STATUS_REG 0x12 +#define II20K_AI_STATUS_INT (1 << 7) +#define II20K_AI_STATUS_TRIG (1 << 6) +#define II20K_AI_STATUS_TRIG_ENA (1 << 5) +#define II20K_AI_STATUS_PACER_ERR (1 << 2) +#define II20K_AI_STATUS_DATA_ERR (1 << 1) +#define II20K_AI_STATUS_SET_TIME_ERR (1 << 0) +#define II20K_AI_LAST_CHAN_ADDR_REG 0x13 +#define II20K_AI_CUR_ADDR_REG 0x14 +#define II20K_AI_SET_TIME_REG 0x15 +#define II20K_AI_DELAY_LSB_REG 0x16 +#define II20K_AI_DELAY_MSB_REG 0x17 +#define II20K_AI_CHAN_ADV_REG 0x18 +#define II20K_AI_CHAN_RESET_REG 0x19 +#define II20K_AI_START_TRIG_REG 0x1a +#define II20K_AI_COUNT_RESET_REG 0x1b +#define II20K_AI_CHANLIST_REG 0x80 +#define II20K_AI_CHANLIST_ONBOARD_ONLY (1 << 5) +#define II20K_AI_CHANLIST_GAIN(x) (((x) & 0x3) << 3) +#define II20K_AI_CHANLIST_MUX_ENA (1 << 2) +#define II20K_AI_CHANLIST_CHAN(x) (((x) & 0x3) << 0) +#define II20K_AI_CHANLIST_LEN 0x80 + +/* the AO range is set by jumpers on the 20006M module */ +static const struct comedi_lrange ii20k_ao_ranges = { + 3, { + BIP_RANGE(5), /* Chan 0 - W1/W3 in Chan 1 - W2/W4 in */ + UNI_RANGE(10), /* Chan 0 - W1/W3 out Chan 1 - W2/W4 in */ + BIP_RANGE(10) /* Chan 0 - W1/W3 in Chan 1 - W2/W4 out */ + } }; -struct pci20xxx_private { - - void *ioaddr; - union pci20xxx_subdev_private subdev_private[PCI20000_MODULES]; +static const struct comedi_lrange ii20k_ai_ranges = { + 4, { + BIP_RANGE(5), /* gain 1 */ + BIP_RANGE(0.5), /* gain 10 */ + BIP_RANGE(0.05), /* gain 100 */ + BIP_RANGE(0.025) /* gain 200 */ + }, }; -#define devpriv ((struct pci20xxx_private *)dev->private) -#define CHAN (CR_CHAN(it->chanlist[0])) - -static int pci20xxx_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pci20xxx_detach(struct comedi_device *dev); - -static struct comedi_driver driver_pci20xxx = { - .driver_name = "ii_pci20kc", - .module = THIS_MODULE, - .attach = pci20xxx_attach, - .detach = pci20xxx_detach, +struct ii20k_ao_private { + unsigned int last_data[2]; }; -static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s, - int opt0, int opt1); -static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s, - int opt0, int opt1); -static int pci20xxx_dio_init(struct comedi_device *dev, - struct comedi_subdevice *s); +struct ii20k_private { + void __iomem *ioaddr; +}; -/* - options[0] Board base address - options[1] IRQ - options[2] first option for module 1 - options[3] second option for module 1 - options[4] first option for module 2 - options[5] second option for module 2 - options[6] first option for module 3 - options[7] second option for module 3 - - options for PCI-20341M: - first Analog input gain configuration - 0 == 1 - 1 == 10 - 2 == 100 - 3 == 200 - - options for PCI-20006M: - first Analog output channel 0 range configuration - 0 == bipolar 10 (-10V -- +10V) - 1 == unipolar 10V (0V -- +10V) - 2 == bipolar 5V (-5V -- +5V) - second Analog output channel 1 range configuration - 0 == bipolar 10 (-10V -- +10V) - 1 == unipolar 10V (0V -- +10V) - 2 == bipolar 5V (-5V -- +5V) -*/ -static int pci20xxx_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static void __iomem *ii20k_module_iobase(struct comedi_device *dev, + struct comedi_subdevice *s) { - unsigned char i; - int ret; - int id; - struct comedi_subdevice *s; - union pci20xxx_subdev_private *sdp; - - ret = alloc_subdevices(dev, 1 + PCI20000_MODULES); - if (ret < 0) - return ret; + struct ii20k_private *devpriv = dev->private; - ret = alloc_private(dev, sizeof(struct pci20xxx_private)); - if (ret < 0) - return ret; - - devpriv->ioaddr = (void *)(unsigned long)it->options[0]; - dev->board_name = "pci20kc"; + return devpriv->ioaddr + (s->index + 1) * II20K_MOD_OFFSET; +} - /* Check PCI-20001 C-2A Carrier Board ID */ - if ((readb(devpriv->ioaddr) & PCI20000_ID) != PCI20000_ID) { - printk(KERN_WARNING "comedi%d: ii_pci20kc PCI-20001" - " C-2A Carrier Board at base=0x%p not found !\n", - dev->minor, devpriv->ioaddr); - return -EINVAL; - } - printk(KERN_INFO "comedi%d: ii_pci20kc: PCI-20001 C-2A at base=0x%p\n", - dev->minor, devpriv->ioaddr); - - for (i = 0; i < PCI20000_MODULES; i++) { - s = dev->subdevices + i; - id = readb(devpriv->ioaddr + (i + 1) * PCI20000_OFFSET); - s->private = devpriv->subdev_private + i; - sdp = s->private; - switch (id) { - case PCI20006_ID: - sdp->pci20006.iobase = - devpriv->ioaddr + (i + 1) * PCI20000_OFFSET; - pci20006_init(dev, s, it->options[2 * i + 2], - it->options[2 * i + 3]); - printk(KERN_INFO "comedi%d: " - "ii_pci20kc PCI-20006 module in slot %d\n", - dev->minor, i + 1); - break; - case PCI20341_ID: - sdp->pci20341.iobase = - devpriv->ioaddr + (i + 1) * PCI20000_OFFSET; - pci20341_init(dev, s, it->options[2 * i + 2], - it->options[2 * i + 3]); - printk(KERN_INFO "comedi%d: " - "ii_pci20kc PCI-20341 module in slot %d\n", - dev->minor, i + 1); - break; - default: - printk(KERN_WARNING "ii_pci20kc: unknown module " - "code 0x%02x in slot %d: module disabled\n", - id, i); /* XXX this looks like a bug! i + 1 ?? */ - /* fall through */ - case PCI20xxx_EMPTY_ID: - s->type = COMEDI_SUBD_UNUSED; - break; - } - } +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; - /* initialize struct pci20xxx_private */ - pci20xxx_dio_init(dev, dev->subdevices + PCI20000_MODULES); + for (i = 0; i < insn->n; i++) + data[i] = ao_spriv->last_data[chan]; - return 1; + return insn->n; } -static int pci20xxx_detach(struct comedi_device *dev) +static int ii20k_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - printk(KERN_INFO "comedi%d: pci20xxx: remove\n", dev->minor); + 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; - return 0; -} + for (i = 0; i < insn->n; i++) { + val = data[i]; -/* pci20006m */ + /* munge data */ + val += ((s->maxdata + 1) >> 1); + val &= s->maxdata; -static int pci20006_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pci20006_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + writeb(val & 0xff, iobase + II20K_AO_LSB_REG(chan)); + writeb((val >> 8) & 0xff, iobase + II20K_AO_MSB_REG(chan)); + writeb(0x00, iobase + II20K_AO_STRB_REG(chan)); + } -static const struct comedi_lrange *pci20006_range_list[] = { - &range_bipolar10, - &range_unipolar10, - &range_bipolar5, -}; + ao_spriv->last_data[chan] = val; -static int pci20006_init(struct comedi_device *dev, struct comedi_subdevice *s, - int opt0, int opt1) -{ - union pci20xxx_subdev_private *sdp = s->private; - - if (opt0 < 0 || opt0 > 2) - opt0 = 0; - if (opt1 < 0 || opt1 > 2) - opt1 = 0; - - sdp->pci20006.ao_range_list[0] = pci20006_range_list[opt0]; - sdp->pci20006.ao_range_list[1] = pci20006_range_list[opt1]; - - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; - s->len_chanlist = 2; - s->insn_read = pci20006_insn_read; - s->insn_write = pci20006_insn_write; - s->maxdata = 0xffff; - s->range_table_list = sdp->pci20006.ao_range_list; - return 0; + return insn->n; } -static int pci20006_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int ii20k_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - union pci20xxx_subdev_private *sdp = s->private; - - data[0] = sdp->pci20006.last_data[CR_CHAN(insn->chanspec)]; + void __iomem *iobase = ii20k_module_iobase(dev, s); + unsigned char status; - return 1; + status = readb(iobase + II20K_AI_STATUS_REG); + if ((status & II20K_AI_STATUS_INT) == 0) + return 0; + return -EBUSY; } -static int pci20006_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void ii20k_ai_setup(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chanspec) { - union pci20xxx_subdev_private *sdp = s->private; - int hi, lo; - unsigned int boarddata; - - sdp->pci20006.last_data[CR_CHAN(insn->chanspec)] = data[0]; - boarddata = (((unsigned int)data[0] + 0x8000) & 0xffff); - /* comedi-data -> board-data */ - lo = (boarddata & 0xff); - hi = ((boarddata >> 8) & 0xff); - - switch (CR_CHAN(insn->chanspec)) { - case 0: - writeb(lo, sdp->iobase + PCI20006_LCHAN0); - writeb(hi, sdp->iobase + PCI20006_LCHAN0 + 1); - writeb(0x00, sdp->iobase + PCI20006_STROBE0); - break; - case 1: - writeb(lo, sdp->iobase + PCI20006_LCHAN1); - writeb(hi, sdp->iobase + PCI20006_LCHAN1 + 1); - writeb(0x00, sdp->iobase + PCI20006_STROBE1); - break; - default: - printk(KERN_WARNING - " comedi%d: pci20xxx: ao channel Error!\n", dev->minor); - return -EINVAL; - } + void __iomem *iobase = ii20k_module_iobase(dev, s); + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned char val; - return 1; -} + /* initialize module */ + writeb(II20K_AI_CONF_ENA, iobase + II20K_AI_CONF_REG); -/* PCI20341M */ + /* software conversion */ + writeb(0, iobase + II20K_AI_STATUS_CMD_REG); -static int pci20341_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + /* set the time base for the settling time counter based on the gain */ + val = (range < 3) ? II20K_AI_OPT_TIMEBASE(0) : II20K_AI_OPT_TIMEBASE(2); + writeb(val, iobase + II20K_AI_OPT_REG); -static const int pci20341_timebase[] = { 0x00, 0x00, 0x00, 0x04 }; -static const int pci20341_settling_time[] = { 0x58, 0x58, 0x93, 0x99 }; + /* set the settling time counter based on the gain */ + val = (range < 2) ? 0x58 : (range < 3) ? 0x93 : 0x99; + writeb(val, iobase + II20K_AI_SET_TIME_REG); -static const struct comedi_lrange range_bipolar0_5 = { - 1, - {BIP_RANGE(0.5)} -}; + /* set number of input channels */ + writeb(1, iobase + II20K_AI_LAST_CHAN_ADDR_REG); -static const struct comedi_lrange range_bipolar0_05 = { - 1, - {BIP_RANGE(0.05)} -}; - -static const struct comedi_lrange range_bipolar0_025 = { - 1, - {BIP_RANGE(0.025)} -}; + /* set the channel list byte */ + val = II20K_AI_CHANLIST_ONBOARD_ONLY | + II20K_AI_CHANLIST_MUX_ENA | + II20K_AI_CHANLIST_GAIN(range) | + II20K_AI_CHANLIST_CHAN(chan); + writeb(val, iobase + II20K_AI_CHANLIST_REG); -static const struct comedi_lrange *const pci20341_ranges[] = { - &range_bipolar5, - &range_bipolar0_5, - &range_bipolar0_05, - &range_bipolar0_025, -}; + /* reset settling time counter and trigger delay counter */ + writeb(0, iobase + II20K_AI_COUNT_RESET_REG); -static int pci20341_init(struct comedi_device *dev, struct comedi_subdevice *s, - int opt0, int opt1) -{ - union pci20xxx_subdev_private *sdp = s->private; - int option; - - /* options handling */ - if (opt0 < 0 || opt0 > 3) - opt0 = 0; - sdp->pci20341.timebase = pci20341_timebase[opt0]; - sdp->pci20341.settling_time = pci20341_settling_time[opt0]; - - /* ai subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - s->n_chan = PCI20341_CHAN_NR; - s->len_chanlist = PCI20341_SCANLIST; - s->insn_read = pci20341_insn_read; - s->maxdata = 0xffff; - s->range_table = pci20341_ranges[opt0]; - - /* depends on gain, trigger, repetition mode */ - option = sdp->pci20341.timebase | PCI20341_REPMODE; - - /* initialize Module */ - writeb(PCI20341_INIT, sdp->iobase + PCI20341_CONFIG_REG); - /* set Pacer */ - writeb(PCI20341_PACER, sdp->iobase + PCI20341_MOD_STATUS); - /* option register */ - writeb(option, sdp->iobase + PCI20341_OPT_REG); - /* settling time counter */ - writeb(sdp->pci20341.settling_time, - sdp->iobase + PCI20341_SET_TIME_REG); - /* trigger not implemented */ - return 0; + /* reset channel scanner */ + writeb(0, iobase + II20K_AI_CHAN_RESET_REG); } -static int pci20341_insn_read(struct comedi_device *dev, +static int ii20k_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - union pci20xxx_subdev_private *sdp = s->private; - unsigned int i = 0, j = 0; - int lo, hi; - unsigned char eoc; /* end of conversion */ - unsigned int clb; /* channel list byte */ - unsigned int boarddata; - - /* write number of input channels */ - writeb(1, sdp->iobase + PCI20341_LCHAN_ADDR_REG); - clb = PCI20341_DAISY_CHAIN | PCI20341_MUX | (sdp->pci20341.ai_gain << 3) - | CR_CHAN(insn->chanspec); - writeb(clb, sdp->iobase + PCI20341_CHAN_LIST); - - /* reset settling time counter and trigger delay counter */ - writeb(0x00, sdp->iobase + PCI20341_CC_RESET); - - writeb(0x00, sdp->iobase + PCI20341_CHAN_RESET); + void __iomem *iobase = ii20k_module_iobase(dev, s); + int ret; + int i; - /* generate Pacer */ + ii20k_ai_setup(dev, s, insn->chanspec); for (i = 0; i < insn->n; i++) { - /* data polling isn't the niciest way to get the data, I know, - * but there are only 6 cycles (mean) and it is easier than - * the whole interrupt stuff - */ - j = 0; - /* generate Pacer */ - readb(sdp->iobase + PCI20341_SOFT_PACER); - - eoc = readb(sdp->iobase + PCI20341_STATUS_REG); - /* poll Interrupt Flag */ - while ((eoc < 0x80) && j < 100) { - j++; - eoc = readb(sdp->iobase + PCI20341_STATUS_REG); - } - if (j >= 100) { - printk(KERN_WARNING - "comedi%d: pci20xxx: " - "AI interrupt channel %i polling exit !\n", - dev->minor, i); - return -EINVAL; - } - lo = readb(sdp->iobase + PCI20341_LDATA); - hi = readb(sdp->iobase + PCI20341_LDATA + 1); - boarddata = lo + 0x100 * hi; - - /* board-data -> comedi-data */ - data[i] = (short)((boarddata + 0x8000) & 0xffff); - } - - return i; -} - -/* native DIO */ + unsigned int val; -static void pci20xxx_dio_config(struct comedi_device *dev, - struct comedi_subdevice *s); -static int pci20xxx_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pci20xxx_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); + /* generate a software start convert signal */ + readb(iobase + II20K_AI_PACER_RESET_REG); -/* initialize struct pci20xxx_private */ -static int pci20xxx_dio_init(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 32; - s->insn_bits = pci20xxx_dio_insn_bits; - s->insn_config = pci20xxx_dio_insn_config; - s->maxdata = 1; - s->len_chanlist = 32; - s->range_table = &range_digital; - s->io_bits = 0; - - /* digital I/O lines default to input on board reset. */ - pci20xxx_dio_config(dev, s); + ret = comedi_timeout(dev, s, insn, ii20k_ai_eoc, 0); + if (ret) + return ret; - return 0; -} + val = readb(iobase + II20K_AI_LSB_REG); + val |= (readb(iobase + II20K_AI_MSB_REG) << 8); -static int pci20xxx_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int mask, bits; - - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x000000ff) - bits = 0x000000ff; - else if (mask & 0x0000ff00) - bits = 0x0000ff00; - else if (mask & 0x00ff0000) - bits = 0x00ff0000; - else - bits = 0xff000000; - if (data[0]) - s->io_bits |= bits; - else - s->io_bits &= ~bits; - pci20xxx_dio_config(dev, s); + /* munge two's complement data */ + val += ((s->maxdata + 1) >> 1); + val &= s->maxdata; - return 1; -} + data[i] = val; + } -static int pci20xxx_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int mask = data[0]; - - s->state &= ~mask; - s->state |= (mask & data[1]); - - mask &= s->io_bits; - if (mask & 0x000000ff) - writeb((s->state >> 0) & 0xff, - devpriv->ioaddr + PCI20000_DIO_0); - if (mask & 0x0000ff00) - writeb((s->state >> 8) & 0xff, - devpriv->ioaddr + PCI20000_DIO_1); - if (mask & 0x00ff0000) - writeb((s->state >> 16) & 0xff, - devpriv->ioaddr + PCI20000_DIO_2); - if (mask & 0xff000000) - writeb((s->state >> 24) & 0xff, - devpriv->ioaddr + PCI20000_DIO_3); - - data[1] = readb(devpriv->ioaddr + PCI20000_DIO_0); - data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8; - data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16; - data[1] |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24; - - return 2; + return insn->n; } -static void pci20xxx_dio_config(struct comedi_device *dev, - struct comedi_subdevice *s) +static void ii20k_dio_config(struct comedi_device *dev, + struct comedi_subdevice *s) { - unsigned char control_01; - unsigned char control_23; - unsigned char buffer; - - control_01 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_01); - control_23 = readb(devpriv->ioaddr + PCI20000_DIO_CONTROL_23); - buffer = readb(devpriv->ioaddr + PCI20000_DIO_BUFFER); + struct ii20k_private *devpriv = dev->private; + unsigned char ctrl01 = 0; + unsigned char ctrl23 = 0; + unsigned char dir_ena = 0; + /* port 0 - channels 0-7 */ if (s->io_bits & 0x000000ff) { - /* output port 0 */ - control_01 &= PCI20000_DIO_EOC; - buffer = (buffer & (~(DIO_BE << DIO_PS_0))) | (DIO_BO << - DIO_PS_0); + /* output port */ + ctrl01 &= ~II20K_CTRL01_DIO0_IN; + dir_ena &= ~II20K_BUF_DISAB_DIO0; + dir_ena |= II20K_DIR_DIO0_OUT; } else { - /* input port 0 */ - control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_EIC; - buffer = (buffer & (~(DIO_BI << DIO_PS_0))); + /* input port */ + ctrl01 |= II20K_CTRL01_DIO0_IN; + dir_ena &= ~II20K_DIR_DIO0_OUT; } + + /* port 1 - channels 8-15 */ if (s->io_bits & 0x0000ff00) { - /* output port 1 */ - control_01 &= PCI20000_DIO_OOC; - buffer = (buffer & (~(DIO_BE << DIO_PS_1))) | (DIO_BO << - DIO_PS_1); + /* output port */ + ctrl01 &= ~II20K_CTRL01_DIO1_IN; + dir_ena &= ~II20K_BUF_DISAB_DIO1; + dir_ena |= II20K_DIR_DIO1_OUT; } else { - /* input port 1 */ - control_01 = (control_01 & DIO_CAND) | PCI20000_DIO_OIC; - buffer = (buffer & (~(DIO_BI << DIO_PS_1))); + /* input port */ + ctrl01 |= II20K_CTRL01_DIO1_IN; + dir_ena &= ~II20K_DIR_DIO1_OUT; } + + /* port 2 - channels 16-23 */ if (s->io_bits & 0x00ff0000) { - /* output port 2 */ - control_23 &= PCI20000_DIO_EOC; - buffer = (buffer & (~(DIO_BE << DIO_PS_2))) | (DIO_BO << - DIO_PS_2); + /* output port */ + ctrl23 &= ~II20K_CTRL23_DIO2_IN; + dir_ena &= ~II20K_BUF_DISAB_DIO2; + dir_ena |= II20K_DIR_DIO2_OUT; } else { - /* input port 2 */ - control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_EIC; - buffer = (buffer & (~(DIO_BI << DIO_PS_2))); + /* input port */ + ctrl23 |= II20K_CTRL23_DIO2_IN; + dir_ena &= ~II20K_DIR_DIO2_OUT; } + + /* port 3 - channels 24-31 */ if (s->io_bits & 0xff000000) { - /* output port 3 */ - control_23 &= PCI20000_DIO_OOC; - buffer = (buffer & (~(DIO_BE << DIO_PS_3))) | (DIO_BO << - DIO_PS_3); + /* output port */ + ctrl23 &= ~II20K_CTRL23_DIO3_IN; + dir_ena &= ~II20K_BUF_DISAB_DIO3; + dir_ena |= II20K_DIR_DIO3_OUT; } else { - /* input port 3 */ - control_23 = (control_23 & DIO_CAND) | PCI20000_DIO_OIC; - buffer = (buffer & (~(DIO_BI << DIO_PS_3))); + /* input port */ + ctrl23 |= II20K_CTRL23_DIO3_IN; + dir_ena &= ~II20K_DIR_DIO3_OUT; } - writeb(control_01, devpriv->ioaddr + PCI20000_DIO_CONTROL_01); - writeb(control_23, devpriv->ioaddr + PCI20000_DIO_CONTROL_23); - writeb(buffer, devpriv->ioaddr + PCI20000_DIO_BUFFER); + + ctrl23 |= II20K_CTRL01_SET; + ctrl23 |= II20K_CTRL23_SET; + + /* order is important */ + writeb(ctrl01, devpriv->ioaddr + II20K_CTRL01_REG); + writeb(ctrl23, devpriv->ioaddr + II20K_CTRL23_REG); + writeb(dir_ena, devpriv->ioaddr + II20K_DIR_ENA_REG); } -#if 0 -static void pci20xxx_do(struct comedi_device *dev, struct comedi_subdevice *s) +static int ii20k_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* XXX if the channel is configured for input, does this - do bad things? */ - /* XXX it would be a good idea to only update the registers - that _need_ to be updated. This requires changes to - comedi, however. */ - writeb((s->state >> 0) & 0xff, devpriv->ioaddr + PCI20000_DIO_0); - writeb((s->state >> 8) & 0xff, devpriv->ioaddr + PCI20000_DIO_1); - writeb((s->state >> 16) & 0xff, devpriv->ioaddr + PCI20000_DIO_2); - writeb((s->state >> 24) & 0xff, devpriv->ioaddr + PCI20000_DIO_3); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 8) + mask = 0x000000ff; + else if (chan < 16) + mask = 0x0000ff00; + else if (chan < 24) + mask = 0x00ff0000; + else + mask = 0xff000000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + ii20k_dio_config(dev, s); + + return insn->n; } -static unsigned int pci20xxx_di(struct comedi_device *dev, - struct comedi_subdevice *s) +static int ii20k_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* XXX same note as above */ - unsigned int bits; + struct ii20k_private *devpriv = dev->private; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x000000ff) + writeb((s->state >> 0) & 0xff, + devpriv->ioaddr + II20K_DIO0_REG); + if (mask & 0x0000ff00) + writeb((s->state >> 8) & 0xff, + devpriv->ioaddr + II20K_DIO1_REG); + if (mask & 0x00ff0000) + writeb((s->state >> 16) & 0xff, + devpriv->ioaddr + II20K_DIO2_REG); + if (mask & 0xff000000) + writeb((s->state >> 24) & 0xff, + devpriv->ioaddr + II20K_DIO3_REG); + } - bits = readb(devpriv->ioaddr + PCI20000_DIO_0); - bits |= readb(devpriv->ioaddr + PCI20000_DIO_1) << 8; - bits |= readb(devpriv->ioaddr + PCI20000_DIO_2) << 16; - bits |= readb(devpriv->ioaddr + PCI20000_DIO_3) << 24; + data[1] = readb(devpriv->ioaddr + II20K_DIO0_REG); + data[1] |= readb(devpriv->ioaddr + II20K_DIO1_REG) << 8; + data[1] |= readb(devpriv->ioaddr + II20K_DIO2_REG) << 16; + data[1] |= readb(devpriv->ioaddr + II20K_DIO3_REG) << 24; - return bits; + return insn->n; } -#endif -static int __init driver_pci20xxx_init_module(void) +static int ii20k_init_module(struct comedi_device *dev, + struct comedi_subdevice *s) { - return comedi_driver_register(&driver_pci20xxx); + struct ii20k_ao_private *ao_spriv; + void __iomem *iobase = ii20k_module_iobase(dev, s); + unsigned char id; + + 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; + break; + case II20K_ID_PCI20341M_1: + /* Analog Input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + s->n_chan = 4; + s->maxdata = 0xffff; + s->range_table = &ii20k_ai_ranges; + s->insn_read = ii20k_ai_insn_read; + break; + default: + s->type = COMEDI_SUBD_UNUSED; + break; + } + + return 0; } -static void __exit driver_pci20xxx_cleanup_module(void) +static int ii20k_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { - comedi_driver_unregister(&driver_pci20xxx); + struct ii20k_private *devpriv; + struct comedi_subdevice *s; + unsigned char id; + bool has_dio; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + devpriv->ioaddr = (void __iomem *)(unsigned long)it->options[0]; + + id = readb(devpriv->ioaddr + II20K_ID_REG); + switch (id & II20K_ID_MASK) { + case II20K_ID_PCI20001C_1A: + has_dio = false; + break; + case II20K_ID_PCI20001C_2A: + has_dio = true; + break; + default: + return -ENODEV; + } + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + s = &dev->subdevices[0]; + if (id & II20K_ID_MOD1_EMPTY) { + s->type = COMEDI_SUBD_UNUSED; + } else { + ret = ii20k_init_module(dev, s); + if (ret) + return ret; + } + + s = &dev->subdevices[1]; + if (id & II20K_ID_MOD2_EMPTY) { + s->type = COMEDI_SUBD_UNUSED; + } else { + ret = ii20k_init_module(dev, s); + if (ret) + return ret; + } + + s = &dev->subdevices[2]; + if (id & II20K_ID_MOD3_EMPTY) { + s->type = COMEDI_SUBD_UNUSED; + } else { + ret = ii20k_init_module(dev, s); + if (ret) + return ret; + } + + /* Digital I/O subdevice */ + s = &dev->subdevices[3]; + if (has_dio) { + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 32; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ii20k_dio_insn_bits; + s->insn_config = ii20k_dio_insn_config; + + /* default all channels to input */ + ii20k_dio_config(dev, s); + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + return 0; } -module_init(driver_pci20xxx_init_module); -module_exit(driver_pci20xxx_cleanup_module); +static struct comedi_driver ii20k_driver = { + .driver_name = "ii_pci20kc", + .module = THIS_MODULE, + .attach = ii20k_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(ii20k_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 8d98cf41270..a8db9d86aad 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -14,96 +14,94 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* -Driver: jr3_pci -Description: JR3/PCI force sensor board -Author: Anders Blomdell <anders.blomdell@control.lth.se> -Status: works -Devices: [JR3] PCI force sensor board (jr3_pci) - - The DSP on the board requires initialization code, which can - be loaded by placing it in /lib/firmware/comedi. - The initialization code should be somewhere on the media you got - with your card. One version is available from http://www.comedi.org - in the comedi_nonfree_firmware tarball. - - Configuration options: - [0] - PCI bus number - if bus number and slot number are 0, - then driver search for first unused card - [1] - PCI slot number - -*/ - -#include "../comedidev.h" + * Driver: jr3_pci + * Description: JR3/PCI force sensor board + * Author: Anders Blomdell <anders.blomdell@control.lth.se> + * Updated: Thu, 01 Nov 2012 17:34:55 +0000 + * Status: works + * Devices: [JR3] PCI force sensor board (jr3_pci) + * + * Configuration options: + * None + * + * Manual configuration of comedi devices is not supported by this + * driver; supported PCI devices are configured as comedi devices + * automatically. + * + * The DSP on the board requires initialization code, which can be + * loaded by placing it in /lib/firmware/comedi. The initialization + * code should be somewhere on the media you got with your card. One + * version is available from http://www.comedi.org in the + * comedi_nonfree_firmware tarball. The file is called "jr3pci.idm". + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> #include <linux/ctype.h> -#include <linux/firmware.h> #include <linux/jiffies.h> #include <linux/slab.h> #include <linux/timer.h> -#include <linux/kernel.h> -#include "comedi_pci.h" + +#include "../comedidev.h" + #include "jr3_pci.h" #define PCI_VENDOR_ID_JR3 0x1762 -#define PCI_DEVICE_ID_JR3_1_CHANNEL 0x3111 -#define PCI_DEVICE_ID_JR3_1_CHANNEL_NEW 0x1111 -#define PCI_DEVICE_ID_JR3_2_CHANNEL 0x3112 -#define PCI_DEVICE_ID_JR3_3_CHANNEL 0x3113 -#define PCI_DEVICE_ID_JR3_4_CHANNEL 0x3114 - -static int jr3_pci_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int jr3_pci_detach(struct comedi_device *dev); - -static struct comedi_driver driver_jr3_pci = { - .driver_name = "jr3_pci", - .module = THIS_MODULE, - .attach = jr3_pci_attach, - .detach = jr3_pci_detach, -}; -static DEFINE_PCI_DEVICE_TABLE(jr3_pci_pci_table) = { - { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_1_CHANNEL_NEW, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_2_CHANNEL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_3_CHANNEL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_JR3, PCI_DEVICE_ID_JR3_4_CHANNEL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, { - 0} +enum jr3_pci_boardid { + BOARD_JR3_1, + BOARD_JR3_2, + BOARD_JR3_3, + BOARD_JR3_4, }; -MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); - -struct jr3_pci_dev_private { +struct jr3_pci_board { + const char *name; + int n_subdevs; +}; - struct pci_dev *pci_dev; - int pci_enabled; - volatile struct jr3_t *iobase; - int n_channels; - struct timer_list timer; +static const struct jr3_pci_board jr3_pci_boards[] = { + [BOARD_JR3_1] = { + .name = "jr3_pci_1", + .n_subdevs = 1, + }, + [BOARD_JR3_2] = { + .name = "jr3_pci_2", + .n_subdevs = 2, + }, + [BOARD_JR3_3] = { + .name = "jr3_pci_3", + .n_subdevs = 3, + }, + [BOARD_JR3_4] = { + .name = "jr3_pci_4", + .n_subdevs = 4, + }, }; -struct poll_delay_t { +struct jr3_pci_transform { + struct { + u16 link_type; + s16 link_amount; + } link[8]; +}; +struct jr3_pci_poll_delay { int min; int max; }; +struct jr3_pci_dev_private { + struct jr3_t __iomem *iobase; + struct timer_list timer; +}; + struct jr3_pci_subdev_private { - volatile struct jr3_channel *channel; + struct jr3_channel __iomem *channel; unsigned long next_time_min; unsigned long next_time_max; enum { state_jr3_poll, @@ -113,7 +111,6 @@ struct jr3_pci_subdev_private { state_jr3_init_use_offset_complete, state_jr3_done } state; - int channel_no; int serial_no; int model_no; struct { @@ -126,67 +123,27 @@ struct jr3_pci_subdev_private { int retries; }; -/* Hotplug firmware loading stuff */ -static int comedi_load_firmware(struct comedi_device *dev, char *name, - int (*cb)(struct comedi_device *dev, - const u8 *data, size_t size)) +static struct jr3_pci_poll_delay poll_delay_min_max(int min, int max) { - int result = 0; - const struct firmware *fw; - char *firmware_path; - static const char *prefix = "comedi/"; - struct jr3_pci_dev_private *devpriv = dev->private; - - firmware_path = kmalloc(strlen(prefix) + strlen(name) + 1, GFP_KERNEL); - if (!firmware_path) { - result = -ENOMEM; - } else { - firmware_path[0] = '\0'; - strcat(firmware_path, prefix); - strcat(firmware_path, name); - result = request_firmware(&fw, firmware_path, - &devpriv->pci_dev->dev); - if (result == 0) { - if (!cb) - result = -EINVAL; - else - result = cb(dev, fw->data, fw->size); - release_firmware(fw); - } - kfree(firmware_path); - } - return result; -} - -static struct poll_delay_t poll_delay_min_max(int min, int max) -{ - struct poll_delay_t result; + struct jr3_pci_poll_delay result; result.min = min; result.max = max; return result; } -static int is_complete(volatile struct jr3_channel *channel) +static int is_complete(struct jr3_channel __iomem *channel) { return get_s16(&channel->command_word0) == 0; } -struct transform_t { - struct { - u16 link_type; - s16 link_amount; - } link[8]; -}; - -static void set_transforms(volatile struct jr3_channel *channel, - struct transform_t transf, short num) +static void set_transforms(struct jr3_channel __iomem *channel, + struct jr3_pci_transform transf, short num) { int i; num &= 0x000f; /* Make sure that 0 <= num <= 15 */ for (i = 0; i < 8; i++) { - set_u16(&channel->transforms[num].link[i].link_type, transf.link[i].link_type); udelay(1); @@ -198,18 +155,18 @@ static void set_transforms(volatile struct jr3_channel *channel, } } -static void use_transform(volatile struct jr3_channel *channel, +static void use_transform(struct jr3_channel __iomem *channel, short transf_num) { set_s16(&channel->command_word0, 0x0500 + (transf_num & 0x000f)); } -static void use_offset(volatile struct jr3_channel *channel, short offset_num) +static void use_offset(struct jr3_channel __iomem *channel, short offset_num) { set_s16(&channel->command_word0, 0x0600 + (offset_num & 0x000f)); } -static void set_offset(volatile struct jr3_channel *channel) +static void set_offset(struct jr3_channel __iomem *channel) { set_s16(&channel->command_word0, 0x0700); } @@ -223,13 +180,9 @@ struct six_axis_t { s16 mz; }; -static void set_full_scales(volatile struct jr3_channel *channel, +static void set_full_scales(struct jr3_channel __iomem *channel, struct six_axis_t full_scale) { - printk("%d %d %d %d %d %d\n", - full_scale.fx, - full_scale.fy, - full_scale.fz, full_scale.mx, full_scale.my, full_scale.mz); set_s16(&channel->full_scale.fx, full_scale.fx); set_s16(&channel->full_scale.fy, full_scale.fy); set_s16(&channel->full_scale.fz, full_scale.fz); @@ -239,7 +192,7 @@ static void set_full_scales(volatile struct jr3_channel *channel, set_s16(&channel->command_word0, 0x0a00); } -static struct six_axis_t get_min_full_scales(volatile struct jr3_channel +static struct six_axis_t get_min_full_scales(struct jr3_channel __iomem *channel) { struct six_axis_t result; @@ -252,7 +205,7 @@ static struct six_axis_t get_min_full_scales(volatile struct jr3_channel return result; } -static struct six_axis_t get_max_full_scales(volatile struct jr3_channel +static struct six_axis_t get_max_full_scales(struct jr3_channel __iomem *channel) { struct six_axis_t result; @@ -265,139 +218,111 @@ static struct six_axis_t get_max_full_scales(volatile struct jr3_channel return result; } +static unsigned int jr3_pci_ai_read_chan(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int val = 0; + + if (spriv->state != state_jr3_done) + return 0; + + if (chan < 56) { + unsigned int axis = chan % 8; + unsigned filter = chan / 8; + + switch (axis) { + case 0: + val = get_s16(&spriv->channel->filter[filter].fx); + break; + case 1: + val = get_s16(&spriv->channel->filter[filter].fy); + break; + case 2: + val = get_s16(&spriv->channel->filter[filter].fz); + break; + case 3: + val = get_s16(&spriv->channel->filter[filter].mx); + break; + case 4: + val = get_s16(&spriv->channel->filter[filter].my); + break; + case 5: + val = get_s16(&spriv->channel->filter[filter].mz); + break; + case 6: + val = get_s16(&spriv->channel->filter[filter].v1); + break; + case 7: + val = get_s16(&spriv->channel->filter[filter].v2); + break; + } + val += 0x4000; + } else if (chan == 56) { + val = get_u16(&spriv->channel->model_no); + } else if (chan == 57) { + val = get_u16(&spriv->channel->serial_no); + } + + return val; +} + static int jr3_pci_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int result; - struct jr3_pci_subdev_private *p; - int channel; - - p = s->private; - channel = CR_CHAN(insn->chanspec); - if (p == NULL || channel > 57) { - result = -EINVAL; - } else { - int i; - - result = insn->n; - if (p->state != state_jr3_done || - (get_u16(&p->channel->errors) & (watch_dog | watch_dog2 | - sensor_change))) { - /* No sensor or sensor changed */ - if (p->state == state_jr3_done) { - /* Restart polling */ - p->state = state_jr3_poll; - } - result = -EAGAIN; - } - for (i = 0; i < insn->n; i++) { - if (channel < 56) { - int axis, filter; - - axis = channel % 8; - filter = channel / 8; - if (p->state != state_jr3_done) { - data[i] = 0; - } else { - int F = 0; - switch (axis) { - case 0:{ - F = get_s16 - (&p->channel->filter - [filter].fx); - } - break; - case 1:{ - F = get_s16 - (&p->channel->filter - [filter].fy); - } - break; - case 2:{ - F = get_s16 - (&p->channel->filter - [filter].fz); - } - break; - case 3:{ - F = get_s16 - (&p->channel->filter - [filter].mx); - } - break; - case 4:{ - F = get_s16 - (&p->channel->filter - [filter].my); - } - break; - case 5:{ - F = get_s16 - (&p->channel->filter - [filter].mz); - } - break; - case 6:{ - F = get_s16 - (&p->channel->filter - [filter].v1); - } - break; - case 7:{ - F = get_s16 - (&p->channel->filter - [filter].v2); - } - break; - } - data[i] = F + 0x4000; - } - } else if (channel == 56) { - if (p->state != state_jr3_done) { - data[i] = 0; - } else { - data[i] = - get_u16(&p->channel->model_no); - } - } else if (channel == 57) { - if (p->state != state_jr3_done) { - data[i] = 0; - } else { - data[i] = - get_u16(&p->channel->serial_no); - } - } + struct jr3_pci_subdev_private *spriv = s->private; + unsigned int chan = CR_CHAN(insn->chanspec); + u16 errors; + int i; + + if (!spriv) + return -EINVAL; + + errors = get_u16(&spriv->channel->errors); + if (spriv->state != state_jr3_done || + (errors & (watch_dog | watch_dog2 | sensor_change))) { + /* No sensor or sensor changed */ + if (spriv->state == state_jr3_done) { + /* Restart polling */ + spriv->state = state_jr3_poll; } + return -EAGAIN; } - return result; + + for (i = 0; i < insn->n; i++) + data[i] = jr3_pci_ai_read_chan(dev, s, chan); + + return insn->n; } static int jr3_pci_open(struct comedi_device *dev) { + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; int i; - struct jr3_pci_dev_private *devpriv = dev->private; - - printk("jr3_pci_open\n"); - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p; - p = dev->subdevices[i].private; - if (p) { - printk("serial: %p %d (%d)\n", p, p->serial_no, - p->channel_no); - } + dev_dbg(dev->class_dev, "jr3_pci_open\n"); + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + if (spriv) + dev_dbg(dev->class_dev, "serial: %p %d (%d)\n", + spriv, spriv->serial_no, s->index); } return 0; } -int read_idm_word(const u8 * data, size_t size, int *pos, unsigned int *val) +static int read_idm_word(const u8 *data, size_t size, int *pos, + unsigned int *val) { int result = 0; - if (pos != 0 && val != 0) { + if (pos && val) { /* Skip over non hex */ - for (; *pos < size && !isxdigit(data[*pos]); (*pos)++) { - } + for (; *pos < size && !isxdigit(data[*pos]); (*pos)++) + ; /* Collect value */ *val = 0; for (; *pos < size; (*pos)++) { @@ -406,337 +331,270 @@ int read_idm_word(const u8 * data, size_t size, int *pos, unsigned int *val) if (value >= 0) { result = 1; *val = (*val << 4) + value; - } else + } else { break; + } } } return result; } -static int jr3_download_firmware(struct comedi_device *dev, const u8 * data, - size_t size) +static int jr3_check_firmware(struct comedi_device *dev, + const u8 *data, size_t size) { + int more = 1; + int pos = 0; + /* * IDM file format is: * { count, address, data <count> } * * ffff */ - int result, more, pos, OK; - - result = 0; - more = 1; - pos = 0; - OK = 0; while (more) { - unsigned int count, addr; + unsigned int count = 0; + unsigned int addr = 0; more = more && read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) { - OK = 1; - break; - } + if (more && count == 0xffff) + return 0; + more = more && read_idm_word(data, size, &pos, &addr); while (more && count > 0) { - unsigned int dummy; + unsigned int dummy = 0; + more = more && read_idm_word(data, size, &pos, &dummy); count--; } } - if (!OK) { - result = -ENODATA; - } else { - int i; - struct jr3_pci_dev_private *p = dev->private; - - for (i = 0; i < p->n_channels; i++) { - struct jr3_pci_subdev_private *sp; - - sp = dev->subdevices[i].private; - more = 1; - pos = 0; - while (more) { - unsigned int count, addr; - more = more - && read_idm_word(data, size, &pos, &count); - if (more && count == 0xffff) - break; - more = more - && read_idm_word(data, size, &pos, &addr); - printk("Loading#%d %4.4x bytes at %4.4x\n", i, - count, addr); - while (more && count > 0) { - if (addr & 0x4000) { - /* 16 bit data, never seen in real life!! */ - unsigned int data1; - - more = more - && read_idm_word(data, - size, &pos, - &data1); - count--; - /* printk("jr3_data, not tested\n"); */ - /* jr3[addr + 0x20000 * pnum] = data1; */ - } else { - /* Download 24 bit program */ - unsigned int data1, data2; - - more = more - && read_idm_word(data, - size, &pos, - &data1); - more = more - && read_idm_word(data, size, - &pos, - &data2); - count -= 2; - if (more) { - set_u16(&p-> - iobase->channel - [i].program_low - [addr], data1); - udelay(1); - set_u16(&p-> - iobase->channel - [i].program_high - [addr], data2); - udelay(1); - - } - } - addr++; + return -ENODATA; +} + +static void jr3_write_firmware(struct comedi_device *dev, + int subdev, const u8 *data, size_t size) +{ + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_t __iomem *iobase = devpriv->iobase; + u32 __iomem *lo; + u32 __iomem *hi; + int more = 1; + int pos = 0; + + while (more) { + unsigned int count = 0; + unsigned int addr = 0; + + more = more && read_idm_word(data, size, &pos, &count); + if (more && count == 0xffff) + return; + + more = more && read_idm_word(data, size, &pos, &addr); + + dev_dbg(dev->class_dev, "Loading#%d %4.4x bytes at %4.4x\n", + subdev, count, addr); + + while (more && count > 0) { + if (addr & 0x4000) { + /* 16 bit data, never seen in real life!! */ + unsigned int data1 = 0; + + more = more && + read_idm_word(data, size, &pos, &data1); + count--; + /* jr3[addr + 0x20000 * pnum] = data1; */ + } else { + /* Download 24 bit program */ + unsigned int data1 = 0; + unsigned int data2 = 0; + + lo = &iobase->channel[subdev].program_lo[addr]; + hi = &iobase->channel[subdev].program_hi[addr]; + + more = more && + read_idm_word(data, size, &pos, &data1); + more = more && + read_idm_word(data, size, &pos, &data2); + count -= 2; + if (more) { + set_u16(lo, data1); + udelay(1); + set_u16(hi, data2); + udelay(1); } } + addr++; } } - return result; } -static struct poll_delay_t jr3_pci_poll_subdevice(struct comedi_subdevice *s) +static int jr3_download_firmware(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) +{ + int subdev; + int ret; + + /* verify IDM file format */ + ret = jr3_check_firmware(dev, data, size); + if (ret) + return ret; + + /* write firmware to each subdevice */ + for (subdev = 0; subdev < dev->n_subdevices; subdev++) + jr3_write_firmware(dev, subdev, data, size); + + return 0; +} + +static struct jr3_pci_poll_delay jr3_pci_poll_subdevice(struct comedi_subdevice *s) { - struct poll_delay_t result = poll_delay_min_max(1000, 2000); - struct jr3_pci_subdev_private *p = s->private; + struct jr3_pci_subdev_private *spriv = s->private; + struct jr3_pci_poll_delay result = poll_delay_min_max(1000, 2000); + struct jr3_channel __iomem *channel; + u16 model_no; + u16 serial_no; + int errors; int i; - if (p) { - volatile struct jr3_channel *channel = p->channel; - int errors = get_u16(&channel->errors); + if (!spriv) + return result; - if (errors != p->errors) { - printk("Errors: %x -> %x\n", p->errors, errors); - p->errors = errors; - } - if (errors & (watch_dog | watch_dog2 | sensor_change)) { - /* Sensor communication lost, force poll mode */ - p->state = state_jr3_poll; + channel = spriv->channel; + errors = get_u16(&channel->errors); + + if (errors != spriv->errors) + spriv->errors = errors; + + /* Sensor communication lost? force poll mode */ + if (errors & (watch_dog | watch_dog2 | sensor_change)) + spriv->state = state_jr3_poll; + switch (spriv->state) { + case state_jr3_poll: + model_no = get_u16(&channel->model_no); + serial_no = get_u16(&channel->serial_no); + + if ((errors & (watch_dog | watch_dog2)) || + model_no == 0 || serial_no == 0) { + /* + * Still no sensor, keep on polling. + * Since it takes up to 10 seconds for offsets to + * stabilize, polling each second should suffice. + */ + } else { + spriv->retries = 0; + spriv->state = state_jr3_init_wait_for_offset; } - switch (p->state) { - case state_jr3_poll:{ - u16 model_no = get_u16(&channel->model_no); - u16 serial_no = get_u16(&channel->serial_no); - if ((errors & (watch_dog | watch_dog2)) || - model_no == 0 || serial_no == 0) { -/* - * Still no sensor, keep on polling. Since it takes up to 10 seconds - * for offsets to stabilize, polling each second should suffice. - */ - result = poll_delay_min_max(1000, 2000); - } else { - p->retries = 0; - p->state = - state_jr3_init_wait_for_offset; - result = poll_delay_min_max(1000, 2000); - } - } - break; - case state_jr3_init_wait_for_offset:{ - p->retries++; - if (p->retries < 10) { - /* Wait for offeset to stabilize (< 10 s according to manual) */ - result = poll_delay_min_max(1000, 2000); - } else { - struct transform_t transf; - - p->model_no = - get_u16(&channel->model_no); - p->serial_no = - get_u16(&channel->serial_no); - - printk - ("Setting transform for channel %d\n", - p->channel_no); - printk("Sensor Model = %i\n", - p->model_no); - printk("Sensor Serial = %i\n", - p->serial_no); - - /* Transformation all zeros */ - for (i = 0; i < ARRAY_SIZE(transf.link); i++) { - transf.link[i].link_type = - (enum link_types)0; - transf.link[i].link_amount = 0; - } - - set_transforms(channel, transf, 0); - use_transform(channel, 0); - p->state = - state_jr3_init_transform_complete; - result = poll_delay_min_max(20, 100); /* Allow 20 ms for completion */ - } - } break; - case state_jr3_init_transform_complete:{ - if (!is_complete(channel)) { - printk - ("state_jr3_init_transform_complete complete = %d\n", - is_complete(channel)); - result = poll_delay_min_max(20, 100); - } else { - /* Set full scale */ - struct six_axis_t min_full_scale; - struct six_axis_t max_full_scale; - - min_full_scale = - get_min_full_scales(channel); - printk("Obtained Min. Full Scales:\n"); - printk("%i ", (min_full_scale).fx); - printk("%i ", (min_full_scale).fy); - printk("%i ", (min_full_scale).fz); - printk("%i ", (min_full_scale).mx); - printk("%i ", (min_full_scale).my); - printk("%i ", (min_full_scale).mz); - printk("\n"); - - max_full_scale = - get_max_full_scales(channel); - printk("Obtained Max. Full Scales:\n"); - printk("%i ", (max_full_scale).fx); - printk("%i ", (max_full_scale).fy); - printk("%i ", (max_full_scale).fz); - printk("%i ", (max_full_scale).mx); - printk("%i ", (max_full_scale).my); - printk("%i ", (max_full_scale).mz); - printk("\n"); - - set_full_scales(channel, - max_full_scale); - - p->state = - state_jr3_init_set_full_scale_complete; - result = poll_delay_min_max(20, 100); /* Allow 20 ms for completion */ - } - } - break; - case state_jr3_init_set_full_scale_complete:{ - if (!is_complete(channel)) { - printk - ("state_jr3_init_set_full_scale_complete complete = %d\n", - is_complete(channel)); - result = poll_delay_min_max(20, 100); - } else { - volatile struct force_array *full_scale; - - /* Use ranges in kN or we will overflow arount 2000N! */ - full_scale = &channel->full_scale; - p->range[0].range.min = - -get_s16(&full_scale->fx) * 1000; - p->range[0].range.max = - get_s16(&full_scale->fx) * 1000; - p->range[1].range.min = - -get_s16(&full_scale->fy) * 1000; - p->range[1].range.max = - get_s16(&full_scale->fy) * 1000; - p->range[2].range.min = - -get_s16(&full_scale->fz) * 1000; - p->range[2].range.max = - get_s16(&full_scale->fz) * 1000; - p->range[3].range.min = - -get_s16(&full_scale->mx) * 100; - p->range[3].range.max = - get_s16(&full_scale->mx) * 100; - p->range[4].range.min = - -get_s16(&full_scale->my) * 100; - p->range[4].range.max = - get_s16(&full_scale->my) * 100; - p->range[5].range.min = - -get_s16(&full_scale->mz) * 100; - p->range[5].range.max = - get_s16(&full_scale->mz) * 100; - p->range[6].range.min = -get_s16(&full_scale->v1) * 100; /* ?? */ - p->range[6].range.max = get_s16(&full_scale->v1) * 100; /* ?? */ - p->range[7].range.min = -get_s16(&full_scale->v2) * 100; /* ?? */ - p->range[7].range.max = get_s16(&full_scale->v2) * 100; /* ?? */ - p->range[8].range.min = 0; - p->range[8].range.max = 65535; - - { - int i; - for (i = 0; i < 9; i++) { - printk("%d %d - %d\n", - i, - p-> - range[i].range. - min, - p-> - range[i].range. - max); - } - } - - use_offset(channel, 0); - p->state = - state_jr3_init_use_offset_complete; - result = poll_delay_min_max(40, 100); /* Allow 40 ms for completion */ - } - } - break; - case state_jr3_init_use_offset_complete:{ - if (!is_complete(channel)) { - printk - ("state_jr3_init_use_offset_complete complete = %d\n", - is_complete(channel)); - result = poll_delay_min_max(20, 100); - } else { - printk - ("Default offsets %d %d %d %d %d %d\n", - get_s16(&channel->offsets.fx), - get_s16(&channel->offsets.fy), - get_s16(&channel->offsets.fz), - get_s16(&channel->offsets.mx), - get_s16(&channel->offsets.my), - get_s16(&channel->offsets.mz)); - - set_s16(&channel->offsets.fx, 0); - set_s16(&channel->offsets.fy, 0); - set_s16(&channel->offsets.fz, 0); - set_s16(&channel->offsets.mx, 0); - set_s16(&channel->offsets.my, 0); - set_s16(&channel->offsets.mz, 0); - - set_offset(channel); - - p->state = state_jr3_done; - } - } - break; - case state_jr3_done:{ - poll_delay_min_max(10000, 20000); - } - break; - default:{ - poll_delay_min_max(1000, 2000); + break; + case state_jr3_init_wait_for_offset: + spriv->retries++; + if (spriv->retries < 10) { + /* + * Wait for offeset to stabilize + * (< 10 s according to manual) + */ + } else { + struct jr3_pci_transform transf; + + spriv->model_no = get_u16(&channel->model_no); + spriv->serial_no = get_u16(&channel->serial_no); + + /* Transformation all zeros */ + for (i = 0; i < ARRAY_SIZE(transf.link); i++) { + transf.link[i].link_type = (enum link_types)0; + transf.link[i].link_amount = 0; } - break; + + set_transforms(channel, transf, 0); + use_transform(channel, 0); + spriv->state = state_jr3_init_transform_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); + } + break; + case state_jr3_init_transform_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + /* Set full scale */ + struct six_axis_t min_full_scale; + struct six_axis_t max_full_scale; + + min_full_scale = get_min_full_scales(channel); + max_full_scale = get_max_full_scales(channel); + set_full_scales(channel, max_full_scale); + + spriv->state = state_jr3_init_set_full_scale_complete; + /* Allow 20 ms for completion */ + result = poll_delay_min_max(20, 100); } + break; + case state_jr3_init_set_full_scale_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + struct force_array __iomem *fs = &channel->full_scale; + + /* Use ranges in kN or we will overflow around 2000N! */ + spriv->range[0].range.min = -get_s16(&fs->fx) * 1000; + spriv->range[0].range.max = get_s16(&fs->fx) * 1000; + spriv->range[1].range.min = -get_s16(&fs->fy) * 1000; + spriv->range[1].range.max = get_s16(&fs->fy) * 1000; + spriv->range[2].range.min = -get_s16(&fs->fz) * 1000; + spriv->range[2].range.max = get_s16(&fs->fz) * 1000; + spriv->range[3].range.min = -get_s16(&fs->mx) * 100; + spriv->range[3].range.max = get_s16(&fs->mx) * 100; + spriv->range[4].range.min = -get_s16(&fs->my) * 100; + spriv->range[4].range.max = get_s16(&fs->my) * 100; + spriv->range[5].range.min = -get_s16(&fs->mz) * 100; + /* the next five are questionable */ + spriv->range[5].range.max = get_s16(&fs->mz) * 100; + spriv->range[6].range.min = -get_s16(&fs->v1) * 100; + spriv->range[6].range.max = get_s16(&fs->v1) * 100; + spriv->range[7].range.min = -get_s16(&fs->v2) * 100; + spriv->range[7].range.max = get_s16(&fs->v2) * 100; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65535; + + use_offset(channel, 0); + spriv->state = state_jr3_init_use_offset_complete; + /* Allow 40 ms for completion */ + result = poll_delay_min_max(40, 100); + } + break; + case state_jr3_init_use_offset_complete: + if (!is_complete(channel)) { + result = poll_delay_min_max(20, 100); + } else { + set_s16(&channel->offsets.fx, 0); + set_s16(&channel->offsets.fy, 0); + set_s16(&channel->offsets.fz, 0); + set_s16(&channel->offsets.mx, 0); + set_s16(&channel->offsets.my, 0); + set_s16(&channel->offsets.mz, 0); + + set_offset(channel); + + spriv->state = state_jr3_done; + } + break; + case state_jr3_done: + result = poll_delay_min_max(10000, 20000); + break; + default: + break; } + return result; } static void jr3_pci_poll_dev(unsigned long data) { - unsigned long flags; struct comedi_device *dev = (struct comedi_device *)data; struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + unsigned long flags; unsigned long now; int delay; int i; @@ -744,25 +602,28 @@ static void jr3_pci_poll_dev(unsigned long data) spin_lock_irqsave(&dev->spinlock, flags); delay = 1000; now = jiffies; - /* Poll all channels that are ready to be polled */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *subdevpriv = - dev->subdevices[i].private; - if (now > subdevpriv->next_time_min) { - struct poll_delay_t sub_delay; - - sub_delay = jr3_pci_poll_subdevice(&dev->subdevices[i]); - subdevpriv->next_time_min = - jiffies + msecs_to_jiffies(sub_delay.min); - subdevpriv->next_time_max = - jiffies + msecs_to_jiffies(sub_delay.max); - if (sub_delay.max && sub_delay.max < delay) { -/* -* Wake up as late as possible -> poll as many channels as possible -* at once -*/ + + /* Poll all channels that are ready to be polled */ + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + + if (now > spriv->next_time_min) { + struct jr3_pci_poll_delay sub_delay; + + sub_delay = jr3_pci_poll_subdevice(s); + + spriv->next_time_min = jiffies + + msecs_to_jiffies(sub_delay.min); + spriv->next_time_max = jiffies + + msecs_to_jiffies(sub_delay.max); + + if (sub_delay.max && sub_delay.max < delay) + /* + * Wake up as late as possible -> + * poll as many channels as possible at once. + */ delay = sub_delay.max; - } } } spin_unlock_irqrestore(&dev->spinlock, flags); @@ -771,180 +632,144 @@ static void jr3_pci_poll_dev(unsigned long data) add_timer(&devpriv->timer); } -static int jr3_pci_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static struct jr3_pci_subdev_private * +jr3_pci_alloc_spriv(struct comedi_device *dev, struct comedi_subdevice *s) { - int result = 0; - struct pci_dev *card = NULL; - int opt_bus, opt_slot, i; - struct jr3_pci_dev_private *devpriv; + struct jr3_pci_dev_private *devpriv = dev->private; + struct jr3_pci_subdev_private *spriv; + int j; + int k; + + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) + return NULL; + + spriv->channel = &devpriv->iobase->channel[s->index].data; + + for (j = 0; j < 8; j++) { + spriv->range[j].length = 1; + spriv->range[j].range.min = -1000000; + spriv->range[j].range.max = 1000000; + + for (k = 0; k < 7; k++) { + spriv->range_table_list[j + k * 8] = + (struct comedi_lrange *)&spriv->range[j]; + spriv->maxdata_list[j + k * 8] = 0x7fff; + } + } + spriv->range[8].length = 1; + spriv->range[8].range.min = 0; + spriv->range[8].range.max = 65536; + + spriv->range_table_list[56] = (struct comedi_lrange *)&spriv->range[8]; + spriv->range_table_list[57] = (struct comedi_lrange *)&spriv->range[8]; + spriv->maxdata_list[56] = 0xffff; + spriv->maxdata_list[57] = 0xffff; - printk("comedi%d: jr3_pci\n", dev->minor); + dev_dbg(dev->class_dev, "p->channel %p %p (%tx)\n", + spriv->channel, devpriv->iobase, + ((char __iomem *)spriv->channel - + (char __iomem *)devpriv->iobase)); + + return spriv; +} - opt_bus = it->options[0]; - opt_slot = it->options[1]; +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; + struct jr3_pci_dev_private *devpriv; + struct jr3_pci_subdev_private *spriv; + struct comedi_subdevice *s; + int ret; + int i; if (sizeof(struct jr3_channel) != 0xc00) { - printk("sizeof(struct jr3_channel) = %x [expected %x]\n", - (unsigned)sizeof(struct jr3_channel), 0xc00); + dev_err(dev->class_dev, + "sizeof(struct jr3_channel) = %x [expected %x]\n", + (unsigned)sizeof(struct jr3_channel), 0xc00); return -EINVAL; } - result = alloc_private(dev, sizeof(struct jr3_pci_dev_private)); - if (result < 0) + if (context < ARRAY_SIZE(jr3_pci_boards)) + board = &jr3_pci_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - card = NULL; - devpriv = dev->private; + init_timer(&devpriv->timer); - while (1) { - card = pci_get_device(PCI_VENDOR_ID_JR3, PCI_ANY_ID, card); - if (card == NULL) { - /* No card found */ - break; - } else { - switch (card->device) { - case PCI_DEVICE_ID_JR3_1_CHANNEL:{ - devpriv->n_channels = 1; - } - break; - case PCI_DEVICE_ID_JR3_1_CHANNEL_NEW:{ - devpriv->n_channels = 1; - } - break; - case PCI_DEVICE_ID_JR3_2_CHANNEL:{ - devpriv->n_channels = 2; - } - break; - case PCI_DEVICE_ID_JR3_3_CHANNEL:{ - devpriv->n_channels = 3; - } - break; - case PCI_DEVICE_ID_JR3_4_CHANNEL:{ - devpriv->n_channels = 4; - } - break; - default:{ - devpriv->n_channels = 0; - } - } - if (devpriv->n_channels >= 1) { - if (opt_bus == 0 && opt_slot == 0) { - /* Take first available card */ - break; - } else if (opt_bus == card->bus->number && - opt_slot == PCI_SLOT(card->devfn)) { - /* Take requested card */ - break; - } - } - } - } - if (!card) { - printk(" no jr3_pci found\n"); - return -EIO; - } else { - devpriv->pci_dev = card; - dev->board_name = "jr3_pci"; - } - result = comedi_pci_enable(card, "jr3_pci"); - if (result < 0) - return -EIO; + ret = comedi_pci_enable(dev); + if (ret) + return ret; - devpriv->pci_enabled = 1; - devpriv->iobase = ioremap(pci_resource_start(card, 0), - offsetof(struct jr3_t, channel[devpriv->n_channels])); + devpriv->iobase = pci_ioremap_bar(pcidev, 0); if (!devpriv->iobase) return -ENOMEM; - result = alloc_subdevices(dev, devpriv->n_channels); - if (result < 0) - goto out; + ret = comedi_alloc_subdevices(dev, board->n_subdevs); + if (ret) + return ret; dev->open = jr3_pci_open; - for (i = 0; i < devpriv->n_channels; i++) { - dev->subdevices[i].type = COMEDI_SUBD_AI; - dev->subdevices[i].subdev_flags = SDF_READABLE | SDF_GROUND; - dev->subdevices[i].n_chan = 8 * 7 + 2; - dev->subdevices[i].insn_read = jr3_pci_ai_insn_read; - dev->subdevices[i].private = - kzalloc(sizeof(struct jr3_pci_subdev_private), GFP_KERNEL); - if (dev->subdevices[i].private) { - struct jr3_pci_subdev_private *p; - int j; - - p = dev->subdevices[i].private; - p->channel = &devpriv->iobase->channel[i].data; - printk("p->channel %p %p (%tx)\n", - p->channel, devpriv->iobase, - ((char *)(p->channel) - - (char *)(devpriv->iobase))); - p->channel_no = i; - for (j = 0; j < 8; j++) { - int k; - - p->range[j].length = 1; - p->range[j].range.min = -1000000; - p->range[j].range.max = 1000000; - for (k = 0; k < 7; k++) { - p->range_table_list[j + k * 8] = - (struct comedi_lrange *)&p-> - range[j]; - p->maxdata_list[j + k * 8] = 0x7fff; - } - } - p->range[8].length = 1; - p->range[8].range.min = 0; - p->range[8].range.max = 65536; - - p->range_table_list[56] = - (struct comedi_lrange *)&p->range[8]; - p->range_table_list[57] = - (struct comedi_lrange *)&p->range[8]; - p->maxdata_list[56] = 0xffff; - p->maxdata_list[57] = 0xffff; - /* Channel specific range and maxdata */ - dev->subdevices[i].range_table = 0; - dev->subdevices[i].range_table_list = - p->range_table_list; - dev->subdevices[i].maxdata = 0; - dev->subdevices[i].maxdata_list = p->maxdata_list; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8 * 7 + 2; + s->insn_read = jr3_pci_ai_insn_read; + + spriv = jr3_pci_alloc_spriv(dev, s); + if (spriv) { + /* Channel specific range and maxdata */ + s->range_table_list = spriv->range_table_list; + s->maxdata_list = spriv->maxdata_list; } } /* Reset DSP card */ - devpriv->iobase->channel[0].reset = 0; - - result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware); - printk("Firmare load %d\n", result); - - if (result < 0) - goto out; -/* - * TODO: use firmware to load preferred offset tables. Suggested - * format: - * model serial Fx Fy Fz Mx My Mz\n - * - * comedi_load_firmware(dev, "jr3_offsets_table", jr3_download_firmware); - */ + writel(0, &devpriv->iobase->channel[0].reset); + + ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + "comedi/jr3pci.idm", + jr3_download_firmware, 0); + dev_dbg(dev->class_dev, "Firmare load %d\n", ret); + if (ret < 0) + return ret; + /* + * TODO: use firmware to load preferred offset tables. Suggested + * format: + * model serial Fx Fy Fz Mx My Mz\n + * + * comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + * "comedi/jr3_offsets_table", + * jr3_download_firmware, 1); + */ -/* - * It takes a few milliseconds for software to settle as much as we - * can read firmware version - */ + /* + * It takes a few milliseconds for software to settle as much as we + * can read firmware version + */ msleep_interruptible(25); for (i = 0; i < 0x18; i++) { - printk("%c", - get_u16(&devpriv->iobase->channel[0]. - data.copyright[i]) >> 8); + dev_dbg(dev->class_dev, "%c\n", + get_u16(&devpriv->iobase->channel[0]. + data.copyright[i]) >> 8); } /* Start card timer */ - for (i = 0; i < devpriv->n_channels; i++) { - struct jr3_pci_subdev_private *p = dev->subdevices[i].private; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; - p->next_time_min = jiffies + msecs_to_jiffies(500); - p->next_time_max = jiffies + msecs_to_jiffies(2000); + spriv->next_time_min = jiffies + msecs_to_jiffies(500); + spriv->next_time_max = jiffies + msecs_to_jiffies(2000); } devpriv->timer.data = (unsigned long)dev; @@ -952,75 +777,54 @@ static int jr3_pci_attach(struct comedi_device *dev, devpriv->timer.expires = jiffies + msecs_to_jiffies(1000); add_timer(&devpriv->timer); -out: - return result; + return 0; } -MODULE_FIRMWARE("comedi/jr3pci.idm"); - -static int jr3_pci_detach(struct comedi_device *dev) +static void jr3_pci_detach(struct comedi_device *dev) { - int i; struct jr3_pci_dev_private *devpriv = dev->private; - printk("comedi%d: jr3_pci: remove\n", dev->minor); if (devpriv) { del_timer_sync(&devpriv->timer); - if (dev->subdevices) { - for (i = 0; i < devpriv->n_channels; i++) - kfree(dev->subdevices[i].private); - } - if (devpriv->iobase) - iounmap((void *)devpriv->iobase); - if (devpriv->pci_enabled) - comedi_pci_disable(devpriv->pci_dev); - - if (devpriv->pci_dev) - pci_dev_put(devpriv->pci_dev); + iounmap(devpriv->iobase); } - return 0; + comedi_pci_disable(dev); } -static int __devinit driver_jr3_pci_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_jr3_pci.driver_name); -} - -static void __devexit driver_jr3_pci_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_jr3_pci_pci_driver = { - .id_table = jr3_pci_pci_table, - .probe = &driver_jr3_pci_pci_probe, - .remove = __devexit_p(&driver_jr3_pci_pci_remove) +static struct comedi_driver jr3_pci_driver = { + .driver_name = "jr3_pci", + .module = THIS_MODULE, + .auto_attach = jr3_pci_auto_attach, + .detach = jr3_pci_detach, }; -static int __init driver_jr3_pci_init_module(void) +static int jr3_pci_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_jr3_pci); - if (retval < 0) - return retval; - - driver_jr3_pci_pci_driver.name = (char *)driver_jr3_pci.driver_name; - return pci_register_driver(&driver_jr3_pci_pci_driver); + return comedi_pci_auto_config(dev, &jr3_pci_driver, id->driver_data); } -static void __exit driver_jr3_pci_cleanup_module(void) -{ - pci_unregister_driver(&driver_jr3_pci_pci_driver); - comedi_driver_unregister(&driver_jr3_pci); -} +static const struct pci_device_id jr3_pci_pci_table[] = { + { PCI_VDEVICE(JR3, 0x1111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3111), BOARD_JR3_1 }, + { PCI_VDEVICE(JR3, 0x3112), BOARD_JR3_2 }, + { PCI_VDEVICE(JR3, 0x3113), BOARD_JR3_3 }, + { PCI_VDEVICE(JR3, 0x3114), BOARD_JR3_4 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, jr3_pci_pci_table); -module_init(driver_jr3_pci_init_module); -module_exit(driver_jr3_pci_cleanup_module); +static struct pci_driver jr3_pci_pci_driver = { + .name = "jr3_pci", + .id_table = jr3_pci_pci_table, + .probe = jr3_pci_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(jr3_pci_driver, jr3_pci_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("comedi/jr3pci.idm"); diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h index a1469611d84..20478ae8fad 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.h +++ b/drivers/staging/comedi/drivers/jr3_pci.h @@ -2,22 +2,22 @@ * is 16 bits, but aligned on a 32 bit PCI boundary */ -static inline u16 get_u16(volatile const u32 * p) +static inline u16 get_u16(const u32 __iomem *p) { - return (u16) readl(p); + return (u16)readl(p); } -static inline void set_u16(volatile u32 * p, u16 val) +static inline void set_u16(u32 __iomem *p, u16 val) { writel(val, p); } -static inline s16 get_s16(volatile const s32 * p) +static inline s16 get_s16(const s32 __iomem *p) { - return (s16) readl(p); + return (s16)readl(p); } -static inline void set_s16(volatile s32 * p, s16 val) +static inline void set_s16(s32 __iomem *p, s16 val) { writel(val, p); } @@ -97,7 +97,7 @@ enum { mz = 0x0020, changeV2 = 0x0040, changeV1 = 0x0080 -} vect_bits_t; +}; /* WARNING_BITS */ /* The warning_bits structure shows the bit pattern for the warning @@ -116,7 +116,7 @@ enum { mx_near_sat = 0x0008, my_near_sat = 0x0010, mz_near_sat = 0x0020 -} warning_bits_t; +}; /* ERROR_BITS */ /* XX_SAT */ @@ -671,11 +671,11 @@ struct jr3_channel { struct jr3_t { struct { - u32 program_low[0x4000]; /* 0x00000 - 0x10000 */ + u32 program_lo[0x4000]; /* 0x00000 - 0x10000 */ struct jr3_channel data; /* 0x10000 - 0x10c00 */ char pad2[0x30000 - 0x00c00]; /* 0x10c00 - 0x40000 */ - u32 program_high[0x8000]; /* 0x40000 - 0x60000 */ - u32 reset; /* 0x60000 - 0x60004 */ + u32 program_hi[0x8000]; /* 0x40000 - 0x60000 */ + u32 reset; /* 0x60000 - 0x60004 */ char pad3[0x20000 - 0x00004]; /* 0x60004 - 0x80000 */ } channel[4]; }; diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index 286093bca3f..ec43c38958d 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -1,299 +1,181 @@ /* - comedi/drivers/ke_counter.c - Comedi driver for Kolter-Electronic PCI Counter 1 Card + * ke_counter.c + * Comedi driver for Kolter-Electronic PCI Counter 1 Card + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ /* -Driver: ke_counter -Description: Driver for Kolter Electronic Counter Card -Devices: [Kolter Electronic] PCI Counter Card (ke_counter) -Author: Michael Hillmann -Updated: Mon, 14 Apr 2008 15:42:42 +0100 -Status: tested - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. - -This driver is a simple driver to read the counter values from -Kolter Electronic PCI Counter Card. -*/ + * Driver: ke_counter + * Description: Driver for Kolter Electronic Counter Card + * Devices: (Kolter Electronic) PCI Counter Card [ke_counter] + * Author: Michael Hillmann + * Updated: Mon, 14 Apr 2008 15:42:42 +0100 + * Status: tested + * + * Configuration Options: not applicable, uses PCI auto config + */ + +#include <linux/module.h> +#include <linux/pci.h> #include "../comedidev.h" -#include "comedi_pci.h" - -#define CNT_DRIVER_NAME "ke_counter" -#define PCI_VENDOR_ID_KOLTER 0x1001 -#define CNT_CARD_DEVICE_ID 0x0014 - -/*-- function prototypes ----------------------------------------------------*/ - -static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int cnt_detach(struct comedi_device *dev); - -static DEFINE_PCI_DEVICE_TABLE(cnt_pci_table) = { - { - PCI_VENDOR_ID_KOLTER, CNT_CARD_DEVICE_ID, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} -}; - -MODULE_DEVICE_TABLE(pci, cnt_pci_table); - -/*-- board specification structure ------------------------------------------*/ - -struct cnt_board_struct { - - const char *name; - int device_id; - int cnt_channel_nbr; - int cnt_bits; -}; - -static const struct cnt_board_struct cnt_boards[] = { - { - .name = CNT_DRIVER_NAME, - .device_id = CNT_CARD_DEVICE_ID, - .cnt_channel_nbr = 3, - .cnt_bits = 24} -}; - -#define cnt_board_nbr (sizeof(cnt_boards)/sizeof(struct cnt_board_struct)) - -/*-- device private structure -----------------------------------------------*/ - -struct cnt_device_private { - - struct pci_dev *pcidev; -}; - -#define devpriv ((struct cnt_device_private *)dev->private) - -static struct comedi_driver cnt_driver = { - .driver_name = CNT_DRIVER_NAME, - .module = THIS_MODULE, - .attach = cnt_attach, - .detach = cnt_detach, -}; - -static int __devinit cnt_driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, cnt_driver.driver_name); -} - -static void __devexit cnt_driver_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver cnt_driver_pci_driver = { - .id_table = cnt_pci_table, - .probe = &cnt_driver_pci_probe, - .remove = __devexit_p(&cnt_driver_pci_remove) -}; - -static int __init cnt_driver_init_module(void) +/* + * PCI BAR 0 Register I/O map + */ +#define KE_RESET_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LATCH_REG(x) (0x00 + ((x) * 0x20)) +#define KE_LSB_REG(x) (0x04 + ((x) * 0x20)) +#define KE_MID_REG(x) (0x08 + ((x) * 0x20)) +#define KE_MSB_REG(x) (0x0c + ((x) * 0x20)) +#define KE_SIGN_REG(x) (0x10 + ((x) * 0x20)) +#define KE_OSC_SEL_REG 0xf8 +#define KE_OSC_SEL_EXT (1 << 0) +#define KE_OSC_SEL_4MHZ (2 << 0) +#define KE_OSC_SEL_20MHZ (3 << 0) +#define KE_DO_REG 0xfc + +static int ke_counter_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int retval; - - retval = comedi_driver_register(&cnt_driver); - if (retval < 0) - return retval; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; + + for (i = 0; i < insn->n; i++) { + val = data[0]; + + /* Order matters */ + outb((val >> 24) & 0xff, dev->iobase + KE_SIGN_REG(chan)); + outb((val >> 16) & 0xff, dev->iobase + KE_MSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + KE_MID_REG(chan)); + outb((val >> 0) & 0xff, dev->iobase + KE_LSB_REG(chan)); + } - cnt_driver_pci_driver.name = (char *)cnt_driver.driver_name; - return pci_register_driver(&cnt_driver_pci_driver); + return insn->n; } -static void __exit cnt_driver_cleanup_module(void) +static int ke_counter_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - pci_unregister_driver(&cnt_driver_pci_driver); - comedi_driver_unregister(&cnt_driver); -} - -module_init(cnt_driver_init_module); -module_exit(cnt_driver_cleanup_module); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; -/*-- counter write ----------------------------------------------------------*/ + for (i = 0; i < insn->n; i++) { + /* Order matters */ + inb(dev->iobase + KE_LATCH_REG(chan)); -/* This should be used only for resetting the counters; maybe it is better - to make a special command 'reset'. */ -static int cnt_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); + val = inb(dev->iobase + KE_LSB_REG(chan)); + val |= (inb(dev->iobase + KE_MID_REG(chan)) << 8); + val |= (inb(dev->iobase + KE_MSB_REG(chan)) << 16); + val |= (inb(dev->iobase + KE_SIGN_REG(chan)) << 24); - outb((unsigned char)((data[0] >> 24) & 0xff), - dev->iobase + chan * 0x20 + 0x10); - outb((unsigned char)((data[0] >> 16) & 0xff), - dev->iobase + chan * 0x20 + 0x0c); - outb((unsigned char)((data[0] >> 8) & 0xff), - dev->iobase + chan * 0x20 + 0x08); - outb((unsigned char)((data[0] >> 0) & 0xff), - dev->iobase + chan * 0x20 + 0x04); + data[i] = val; + } - /* return the number of samples written */ - return 1; + return insn->n; } -/*-- counter read -----------------------------------------------------------*/ - -static int cnt_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int ke_counter_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned char a0, a1, a2, a3, a4; - int chan = CR_CHAN(insn->chanspec); - int result; - - a0 = inb(dev->iobase + chan * 0x20); - a1 = inb(dev->iobase + chan * 0x20 + 0x04); - a2 = inb(dev->iobase + chan * 0x20 + 0x08); - a3 = inb(dev->iobase + chan * 0x20 + 0x0c); - a4 = inb(dev->iobase + chan * 0x20 + 0x10); + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + KE_DO_REG); - result = (a1 + (a2 * 256) + (a3 * 65536)); - if (a4 > 0) - result = result - s->maxdata; + data[1] = s->state; - *data = (unsigned int)result; - - /* return the number of samples read */ - return 1; + return insn->n; } -/*-- attach -----------------------------------------------------------------*/ - -static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int ke_counter_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - struct comedi_subdevice *subdevice; - struct pci_dev *pci_device = NULL; - struct cnt_board_struct *board; - unsigned long io_base; - int error, i; - - /* allocate device private structure */ - error = alloc_private(dev, sizeof(struct cnt_device_private)); - if (error < 0) - return error; - - /* Probe the device to determine what device in the series it is. */ - for_each_pci_dev(pci_device) { - if (pci_device->vendor == PCI_VENDOR_ID_KOLTER) { - for (i = 0; i < cnt_board_nbr; i++) { - if (cnt_boards[i].device_id == - pci_device->device) { - /* was a particular bus/slot requested? */ - if ((it->options[0] != 0) - || (it->options[1] != 0)) { - /* are we on the wrong bus/slot? */ - if (pci_device->bus->number != - it->options[0] - || - PCI_SLOT(pci_device->devfn) - != it->options[1]) { - continue; - } - } - - dev->board_ptr = cnt_boards + i; - board = - (struct cnt_board_struct *) - dev->board_ptr; - goto found; - } - } - } - } - printk(KERN_WARNING - "comedi%d: no supported board found! (req. bus/slot: %d/%d)\n", - dev->minor, it->options[0], it->options[1]); - return -EIO; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct comedi_subdevice *s; + int ret; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 0); + + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 3; + s->maxdata = 0x01ffffff; + s->range_table = &range_unknown; + s->insn_read = ke_counter_insn_read; + s->insn_write = ke_counter_insn_write; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 3; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ke_counter_do_insn_bits; + + outb(KE_OSC_SEL_20MHZ, dev->iobase + KE_OSC_SEL_REG); + + outb(0, dev->iobase + KE_RESET_REG(0)); + outb(0, dev->iobase + KE_RESET_REG(1)); + outb(0, dev->iobase + KE_RESET_REG(2)); -found: - printk(KERN_INFO - "comedi%d: found %s at PCI bus %d, slot %d\n", dev->minor, - board->name, pci_device->bus->number, - PCI_SLOT(pci_device->devfn)); - devpriv->pcidev = pci_device; - dev->board_name = board->name; - - /* enable PCI device and request regions */ - error = comedi_pci_enable(pci_device, CNT_DRIVER_NAME); - if (error < 0) { - printk(KERN_WARNING "comedi%d: " - "failed to enable PCI device and request regions!\n", - dev->minor); - return error; - } - - /* read register base address [PCI_BASE_ADDRESS #0] */ - io_base = pci_resource_start(pci_device, 0); - dev->iobase = io_base; - - /* allocate the subdevice structures */ - error = alloc_subdevices(dev, 1); - if (error < 0) - return error; - - subdevice = dev->subdevices + 0; - dev->read_subdev = subdevice; - - subdevice->type = COMEDI_SUBD_COUNTER; - subdevice->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; - subdevice->n_chan = board->cnt_channel_nbr; - subdevice->maxdata = (1 << board->cnt_bits) - 1; - subdevice->insn_read = cnt_rinsn; - subdevice->insn_write = cnt_winsn; - - /* select 20MHz clock */ - outb(3, dev->iobase + 248); - - /* reset all counters */ - outb(0, dev->iobase); - outb(0, dev->iobase + 0x20); - outb(0, dev->iobase + 0x40); - - printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " attached.\n", - dev->minor); return 0; } -/*-- detach -----------------------------------------------------------------*/ +static struct comedi_driver ke_counter_driver = { + .driver_name = "ke_counter", + .module = THIS_MODULE, + .auto_attach = ke_counter_auto_attach, + .detach = comedi_pci_disable, +}; -static int cnt_detach(struct comedi_device *dev) +static int ke_counter_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - if (devpriv && devpriv->pcidev) { - if (dev->iobase) - comedi_pci_disable(devpriv->pcidev); - pci_dev_put(devpriv->pcidev); - } - printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " remove\n", - dev->minor); - return 0; + return comedi_pci_auto_config(dev, &ke_counter_driver, + id->driver_data); } +static const struct pci_device_id ke_counter_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_KOLTER, 0x0014) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ke_counter_pci_table); + +static struct pci_driver ke_counter_pci_driver = { + .name = "ke_counter", + .id_table = ke_counter_pci_table, + .probe = ke_counter_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(ke_counter_driver, ke_counter_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Kolter Electronic Counter Card"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index b692fea0d2b..25ce2f78db8 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: me4000 @@ -35,13 +30,7 @@ Supports: - Digital I/O - Counter -Configuration Options: - - [0] - PCI bus number (optional) - [1] - PCI slot number (optional) - - If bus/slot is not specified, the first available PCI - device will be used. +Configuration Options: not applicable, uses PCI auto config The firmware required by these boards is available in the comedi_nonfree_firmware tarball available from @@ -51,725 +40,301 @@ broken. */ -#include <linux/interrupt.h> -#include "../comedidev.h" - +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include <linux/list.h> #include <linux/spinlock.h> -#include "comedi_pci.h" -#include "me4000.h" +#include "../comedidev.h" + +#include "comedi_fc.h" +#include "8253.h" +#include "plx9052.h" + #if 0 /* file removed due to GPL incompatibility */ #include "me4000_fw.h" #endif -/*============================================================================= - PCI device table. - This is used by modprobe to translate PCI IDs to drivers. - ===========================================================================*/ - -static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) }, - { 0 } -}; - -MODULE_DEVICE_TABLE(pci, me4000_pci_table); - -static const struct me4000_board me4000_boards[] = { - {"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} }, - - {"ME-4660", 0x4660, {0, 0}, {32, 0, 16, 0}, {4}, {3} }, - {"ME-4660i", 0x4661, {0, 0}, {32, 0, 16, 0}, {4}, {3} }, - {"ME-4660s", 0x4662, {0, 0}, {32, 8, 16, 0}, {4}, {3} }, - {"ME-4660is", 0x4663, {0, 0}, {32, 8, 16, 0}, {4}, {3} }, - - {"ME-4670", 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4670i", 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4670s", 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3} }, - {"ME-4670is", 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3} }, - - {"ME-4680", 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4680i", 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4680s", 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3} }, - {"ME-4680is", 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3} }, - - {0}, +/* + * ME4000 Register map and bit defines + */ +#define ME4000_AO_CHAN(x) ((x) * 0x18) + +#define ME4000_AO_CTRL_REG(x) (0x00 + ME4000_AO_CHAN(x)) +#define ME4000_AO_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_AO_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_AO_CTRL_MASK_MODE (3 << 0) +#define ME4000_AO_CTRL_BIT_STOP (1 << 2) +#define ME4000_AO_CTRL_BIT_ENABLE_FIFO (1 << 3) +#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG (1 << 4) +#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE (1 << 5) +#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP (1 << 7) +#define ME4000_AO_CTRL_BIT_ENABLE_DO (1 << 8) +#define ME4000_AO_CTRL_BIT_ENABLE_IRQ (1 << 9) +#define ME4000_AO_CTRL_BIT_RESET_IRQ (1 << 10) +#define ME4000_AO_STATUS_REG(x) (0x04 + ME4000_AO_CHAN(x)) +#define ME4000_AO_STATUS_BIT_FSM (1 << 0) +#define ME4000_AO_STATUS_BIT_FF (1 << 1) +#define ME4000_AO_STATUS_BIT_HF (1 << 2) +#define ME4000_AO_STATUS_BIT_EF (1 << 3) +#define ME4000_AO_FIFO_REG(x) (0x08 + ME4000_AO_CHAN(x)) +#define ME4000_AO_SINGLE_REG(x) (0x0c + ME4000_AO_CHAN(x)) +#define ME4000_AO_TIMER_REG(x) (0x10 + ME4000_AO_CHAN(x)) +#define ME4000_AI_CTRL_REG 0x74 +#define ME4000_AI_STATUS_REG 0x74 +#define ME4000_AI_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_AI_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_AI_CTRL_BIT_MODE_2 (1 << 2) +#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD (1 << 3) +#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP (1 << 4) +#define ME4000_AI_CTRL_BIT_STOP (1 << 5) +#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO (1 << 6) +#define ME4000_AI_CTRL_BIT_DATA_FIFO (1 << 7) +#define ME4000_AI_CTRL_BIT_FULLSCALE (1 << 8) +#define ME4000_AI_CTRL_BIT_OFFSET (1 << 9) +#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG (1 << 10) +#define ME4000_AI_CTRL_BIT_EX_TRIG (1 << 11) +#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING (1 << 12) +#define ME4000_AI_CTRL_BIT_EX_IRQ (1 << 13) +#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET (1 << 14) +#define ME4000_AI_CTRL_BIT_LE_IRQ (1 << 15) +#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET (1 << 16) +#define ME4000_AI_CTRL_BIT_HF_IRQ (1 << 17) +#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET (1 << 18) +#define ME4000_AI_CTRL_BIT_SC_IRQ (1 << 19) +#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET (1 << 20) +#define ME4000_AI_CTRL_BIT_SC_RELOAD (1 << 21) +#define ME4000_AI_STATUS_BIT_EF_CHANNEL (1 << 22) +#define ME4000_AI_STATUS_BIT_HF_CHANNEL (1 << 23) +#define ME4000_AI_STATUS_BIT_FF_CHANNEL (1 << 24) +#define ME4000_AI_STATUS_BIT_EF_DATA (1 << 25) +#define ME4000_AI_STATUS_BIT_HF_DATA (1 << 26) +#define ME4000_AI_STATUS_BIT_FF_DATA (1 << 27) +#define ME4000_AI_STATUS_BIT_LE (1 << 28) +#define ME4000_AI_STATUS_BIT_FSM (1 << 29) +#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31) +#define ME4000_AI_CHANNEL_LIST_REG 0x78 +#define ME4000_AI_LIST_INPUT_SINGLE_ENDED (0 << 5) +#define ME4000_AI_LIST_INPUT_DIFFERENTIAL (1 << 5) +#define ME4000_AI_LIST_RANGE_BIPOLAR_10 (0 << 6) +#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 (1 << 6) +#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 (2 << 6) +#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 (3 << 6) +#define ME4000_AI_LIST_LAST_ENTRY (1 << 8) +#define ME4000_AI_DATA_REG 0x7c +#define ME4000_AI_CHAN_TIMER_REG 0x80 +#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 +#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 +#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8c +#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 +#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 +#define ME4000_AI_START_REG 0x98 +#define ME4000_IRQ_STATUS_REG 0x9c +#define ME4000_IRQ_STATUS_BIT_EX (1 << 0) +#define ME4000_IRQ_STATUS_BIT_LE (1 << 1) +#define ME4000_IRQ_STATUS_BIT_AI_HF (1 << 2) +#define ME4000_IRQ_STATUS_BIT_AO_0_HF (1 << 3) +#define ME4000_IRQ_STATUS_BIT_AO_1_HF (1 << 4) +#define ME4000_IRQ_STATUS_BIT_AO_2_HF (1 << 5) +#define ME4000_IRQ_STATUS_BIT_AO_3_HF (1 << 6) +#define ME4000_IRQ_STATUS_BIT_SC (1 << 7) +#define ME4000_DIO_PORT_0_REG 0xa0 +#define ME4000_DIO_PORT_1_REG 0xa4 +#define ME4000_DIO_PORT_2_REG 0xa8 +#define ME4000_DIO_PORT_3_REG 0xac +#define ME4000_DIO_DIR_REG 0xb0 +#define ME4000_AO_LOADSETREG_XX 0xb4 +#define ME4000_DIO_CTRL_REG 0xb8 +#define ME4000_DIO_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_DIO_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_DIO_CTRL_BIT_MODE_2 (1 << 2) +#define ME4000_DIO_CTRL_BIT_MODE_3 (1 << 3) +#define ME4000_DIO_CTRL_BIT_MODE_4 (1 << 4) +#define ME4000_DIO_CTRL_BIT_MODE_5 (1 << 5) +#define ME4000_DIO_CTRL_BIT_MODE_6 (1 << 6) +#define ME4000_DIO_CTRL_BIT_MODE_7 (1 << 7) +#define ME4000_DIO_CTRL_BIT_FUNCTION_0 (1 << 8) +#define ME4000_DIO_CTRL_BIT_FUNCTION_1 (1 << 9) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 (1 << 10) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 (1 << 11) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 (1 << 12) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 (1 << 13) +#define ME4000_AO_DEMUX_ADJUST_REG 0xbc +#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4c +#define ME4000_AI_SAMPLE_COUNTER_REG 0xc0 + +#define ME4000_AI_FIFO_COUNT 2048 + +#define ME4000_AI_MIN_TICKS 66 +#define ME4000_AI_MIN_SAMPLE_TIME 2000 +#define ME4000_AI_BASE_FREQUENCY (unsigned int) 33E6 + +#define ME4000_AI_CHANNEL_LIST_COUNT 1024 + +struct me4000_info { + unsigned long plx_regbase; + unsigned long timer_regbase; + + unsigned int ao_readback[4]; }; -#define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1) - -/*----------------------------------------------------------------------------- - Comedi function prototypes - ---------------------------------------------------------------------------*/ -static int me4000_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int me4000_detach(struct comedi_device *dev); -static struct comedi_driver driver_me4000 = { - .driver_name = "me4000", - .module = THIS_MODULE, - .attach = me4000_attach, - .detach = me4000_detach, +enum me4000_boardid { + BOARD_ME4650, + BOARD_ME4660, + BOARD_ME4660I, + BOARD_ME4660S, + BOARD_ME4660IS, + BOARD_ME4670, + BOARD_ME4670I, + BOARD_ME4670S, + BOARD_ME4670IS, + BOARD_ME4680, + BOARD_ME4680I, + BOARD_ME4680S, + BOARD_ME4680IS, }; -/*----------------------------------------------------------------------------- - Meilhaus function prototypes - ---------------------------------------------------------------------------*/ -static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it); -static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p); -static int init_board_info(struct comedi_device *dev, - struct pci_dev *pci_dev_p); -static int init_ao_context(struct comedi_device *dev); -static int init_ai_context(struct comedi_device *dev); -static int init_dio_context(struct comedi_device *dev); -static int init_cnt_context(struct comedi_device *dev); -static int xilinx_download(struct comedi_device *dev); -static int reset_board(struct comedi_device *dev); - -static int me4000_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int cnt_reset(struct comedi_device *dev, unsigned int channel); - -static int cnt_config(struct comedi_device *dev, - unsigned int channel, unsigned int mode); - -static int me4000_cnt_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_cnt_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_cnt_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *subdevice, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - -static int ai_check_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -static int ai_round_cmd_args(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd, - unsigned int *init_ticks, - unsigned int *scan_ticks, - unsigned int *chan_ticks); - -static int ai_prepare(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd, - unsigned int init_ticks, - unsigned int scan_ticks, unsigned int chan_ticks); - -static int ai_write_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -static irqreturn_t me4000_ai_isr(int irq, void *dev_id); - -static int me4000_ai_do_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -static int me4000_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); - -static int me4000_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int me4000_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/*----------------------------------------------------------------------------- - Meilhaus inline functions - ---------------------------------------------------------------------------*/ - -static inline void me4000_outb(struct comedi_device *dev, unsigned char value, - unsigned long port) -{ - PORT_PDEBUG("--> 0x%02X port 0x%04lX\n", value, port); - outb(value, port); -} - -static inline void me4000_outl(struct comedi_device *dev, unsigned long value, - unsigned long port) -{ - PORT_PDEBUG("--> 0x%08lX port 0x%04lX\n", value, port); - outl(value, port); -} - -static inline unsigned long me4000_inl(struct comedi_device *dev, - unsigned long port) -{ - unsigned long value; - value = inl(port); - PORT_PDEBUG("<-- 0x%08lX port 0x%04lX\n", value, port); - return value; -} - -static inline unsigned char me4000_inb(struct comedi_device *dev, - unsigned long port) -{ - unsigned char value; - value = inb(port); - PORT_PDEBUG("<-- 0x%08X port 0x%04lX\n", value, port); - return value; -} - -static const struct comedi_lrange me4000_ai_range = { - 4, - { - UNI_RANGE(2.5), - UNI_RANGE(10), - BIP_RANGE(2.5), - BIP_RANGE(10), - } +struct me4000_board { + const char *name; + int ao_nchan; + int ao_fifo; + int ai_nchan; + int ai_diff_nchan; + int ai_sh_nchan; + int ex_trig_analog; + int dio_nchan; + int has_counter; }; -static const struct comedi_lrange me4000_ao_range = { - 1, - { - BIP_RANGE(10), - } +static const struct me4000_board me4000_boards[] = { + [BOARD_ME4650] = { + .name = "ME-4650", + .ai_nchan = 16, + .dio_nchan = 32, + }, + [BOARD_ME4660] = { + .name = "ME-4660", + .ai_nchan = 32, + .ai_diff_nchan = 16, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4660I] = { + .name = "ME-4660i", + .ai_nchan = 32, + .ai_diff_nchan = 16, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4660S] = { + .name = "ME-4660s", + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4660IS] = { + .name = "ME-4660is", + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4670] = { + .name = "ME-4670", + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4670I] = { + .name = "ME-4670i", + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4670S] = { + .name = "ME-4670s", + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4670IS] = { + .name = "ME-4670is", + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4680] = { + .name = "ME-4680", + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4680I] = { + .name = "ME-4680i", + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4680S] = { + .name = "ME-4680s", + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, + [BOARD_ME4680IS] = { + .name = "ME-4680is", + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, }; -static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int result; - - CALL_PDEBUG("In me4000_attach()\n"); - - result = me4000_probe(dev, it); - if (result) - return result; - - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. It relies on - * n_subdevices being set correctly. - */ - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - /*========================================================================= - Analog input subdevice - ========================================================================*/ - - s = dev->subdevices + 0; - - if (thisboard->ai.count) { - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; - s->n_chan = thisboard->ai.count; - s->maxdata = 0xFFFF; /* 16 bit ADC */ - s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; - s->range_table = &me4000_ai_range; - s->insn_read = me4000_ai_insn_read; - - if (info->irq > 0) { - if (request_irq(info->irq, me4000_ai_isr, - IRQF_SHARED, "ME-4000", dev)) { - printk - ("comedi%d: me4000: me4000_attach(): " - "Unable to allocate irq\n", dev->minor); - } else { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->cancel = me4000_ai_cancel; - s->do_cmdtest = me4000_ai_do_cmd_test; - s->do_cmd = me4000_ai_do_cmd; - } - } else { - printk(KERN_WARNING - "comedi%d: me4000: me4000_attach(): " - "No interrupt available\n", dev->minor); - } - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /*========================================================================= - Analog output subdevice - ========================================================================*/ - - s = dev->subdevices + 1; - - if (thisboard->ao.count) { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND; - s->n_chan = thisboard->ao.count; - s->maxdata = 0xFFFF; /* 16 bit DAC */ - s->range_table = &me4000_ao_range; - s->insn_write = me4000_ao_insn_write; - s->insn_read = me4000_ao_insn_read; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /*========================================================================= - Digital I/O subdevice - ========================================================================*/ - - s = dev->subdevices + 2; - - if (thisboard->dio.count) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->dio.count * 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = me4000_dio_insn_bits; - s->insn_config = me4000_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - /* - * Check for optoisolated ME-4000 version. If one the first - * port is a fixed output port and the second is a fixed input port. - */ - if (!me4000_inl(dev, info->dio_context.dir_reg)) { - s->io_bits |= 0xFF; - me4000_outl(dev, ME4000_DIO_CTRL_BIT_MODE_0, - info->dio_context.dir_reg); - } - - /*========================================================================= - Counter subdevice - ========================================================================*/ - - s = dev->subdevices + 3; - - if (thisboard->cnt.count) { - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->cnt.count; - s->maxdata = 0xFFFF; /* 16 bit counters */ - s->insn_read = me4000_cnt_insn_read; - s->insn_write = me4000_cnt_insn_write; - s->insn_config = me4000_cnt_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - return 0; -} - -static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct pci_dev *pci_device = NULL; - int result, i; - struct me4000_board *board; - - CALL_PDEBUG("In me4000_probe()\n"); - - /* Allocate private memory */ - if (alloc_private(dev, sizeof(struct me4000_info)) < 0) - return -ENOMEM; - - /* - * Probe the device to determine what device in the series it is. - */ - for_each_pci_dev(pci_device) { - if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) { - for (i = 0; i < ME4000_BOARD_VERSIONS; i++) { - if (me4000_boards[i].device_id == - pci_device->device) { - /* - * Was a particular - * bus/slot requested? - */ - if ((it->options[0] != 0) - || (it->options[1] != 0)) { - /* - * Are we on the wrong - * bus/slot? - */ - if (pci_device->bus->number != - it->options[0] - || - PCI_SLOT(pci_device->devfn) - != it->options[1]) { - continue; - } - } - dev->board_ptr = me4000_boards + i; - board = - (struct me4000_board *) - dev->board_ptr; - info->pci_dev_p = pci_device; - goto found; - } - } - } - } - - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "No supported board found (req. bus/slot : %d/%d)\n", - dev->minor, it->options[0], it->options[1]); - return -ENODEV; - -found: - - printk(KERN_INFO - "comedi%d: me4000: me4000_probe(): " - "Found %s at PCI bus %d, slot %d\n", - dev->minor, me4000_boards[i].name, pci_device->bus->number, - PCI_SLOT(pci_device->devfn)); - - /* Set data in device structure */ - dev->board_name = board->name; - - /* Enable PCI device and request regions */ - result = comedi_pci_enable(pci_device, dev->board_name); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): Cannot enable PCI " - "device and request I/O regions\n", dev->minor); - return result; - } - - /* Get the PCI base registers */ - result = get_registers(dev, pci_device); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot get registers\n", dev->minor); - return result; - } - /* Initialize board info */ - result = init_board_info(dev, pci_device); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init baord info\n", dev->minor); - return result; - } - - /* Init analog output context */ - result = init_ao_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init ao context\n", dev->minor); - return result; - } - - /* Init analog input context */ - result = init_ai_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init ai context\n", dev->minor); - return result; - } - - /* Init digital I/O context */ - result = init_dio_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init dio context\n", dev->minor); - return result; - } - - /* Init counter context */ - result = init_cnt_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init cnt context\n", dev->minor); - return result; - } - - /* Download the xilinx firmware */ - result = xilinx_download(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Can't download firmware\n", dev->minor); - return result; - } - - /* Make a hardware reset */ - result = reset_board(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): Can't reset board\n", - dev->minor); - return result; - } - - return 0; -} - -static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p) -{ - - CALL_PDEBUG("In get_registers()\n"); - - /*--------------------------- plx regbase -------------------------------*/ - - info->plx_regbase = pci_resource_start(pci_dev_p, 1); - if (info->plx_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 1 is not available\n", dev->minor); - return -ENODEV; - } - info->plx_regbase_size = pci_resource_len(pci_dev_p, 1); - - /*--------------------------- me4000 regbase ----------------------------*/ - - info->me4000_regbase = pci_resource_start(pci_dev_p, 2); - if (info->me4000_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 2 is not available\n", dev->minor); - return -ENODEV; - } - info->me4000_regbase_size = pci_resource_len(pci_dev_p, 2); - - /*--------------------------- timer regbase ------------------------------*/ - - info->timer_regbase = pci_resource_start(pci_dev_p, 3); - if (info->timer_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 3 is not available\n", dev->minor); - return -ENODEV; - } - info->timer_regbase_size = pci_resource_len(pci_dev_p, 3); - - /*--------------------------- program regbase ----------------------------*/ - - info->program_regbase = pci_resource_start(pci_dev_p, 5); - if (info->program_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 5 is not available\n", dev->minor); - return -ENODEV; - } - info->program_regbase_size = pci_resource_len(pci_dev_p, 5); - - return 0; -} - -static int init_board_info(struct comedi_device *dev, struct pci_dev *pci_dev_p) -{ - int result; - - CALL_PDEBUG("In init_board_info()\n"); - - /* Init spin locks */ - /* spin_lock_init(&info->preload_lock); */ - /* spin_lock_init(&info->ai_ctrl_lock); */ - - /* Get the serial number */ - result = pci_read_config_dword(pci_dev_p, 0x2C, &info->serial_no); - if (result != PCIBIOS_SUCCESSFUL) - return result; - - /* Get the hardware revision */ - result = pci_read_config_byte(pci_dev_p, 0x08, &info->hw_revision); - if (result != PCIBIOS_SUCCESSFUL) - return result; - - /* Get the vendor id */ - info->vendor_id = pci_dev_p->vendor; - - /* Get the device id */ - info->device_id = pci_dev_p->device; - - /* Get the irq assigned to the board */ - info->irq = pci_dev_p->irq; - - return 0; -} - -static int init_ao_context(struct comedi_device *dev) -{ - int i; - - CALL_PDEBUG("In init_ao_context()\n"); - - for (i = 0; i < thisboard->ao.count; i++) { - /* spin_lock_init(&info->ao_context[i].use_lock); */ - info->ao_context[i].irq = info->irq; - - switch (i) { - case 0: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_00_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_00_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_00_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_00_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_00_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 1: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_01_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_01_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_01_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_01_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_01_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 2: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_02_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_02_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_02_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_02_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_02_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 3: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_03_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_03_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_03_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_03_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_03_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - default: - break; - } +static const struct comedi_lrange me4000_ai_range = { + 4, { + UNI_RANGE(2.5), + UNI_RANGE(10), + BIP_RANGE(2.5), + BIP_RANGE(10) } - - return 0; -} - -static int init_ai_context(struct comedi_device *dev) -{ - - CALL_PDEBUG("In init_ai_context()\n"); - - info->ai_context.irq = info->irq; - - info->ai_context.ctrl_reg = info->me4000_regbase + ME4000_AI_CTRL_REG; - info->ai_context.status_reg = - info->me4000_regbase + ME4000_AI_STATUS_REG; - info->ai_context.channel_list_reg = - info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG; - info->ai_context.data_reg = info->me4000_regbase + ME4000_AI_DATA_REG; - info->ai_context.chan_timer_reg = - info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG; - info->ai_context.chan_pre_timer_reg = - info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG; - info->ai_context.scan_timer_low_reg = - info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG; - info->ai_context.scan_timer_high_reg = - info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG; - info->ai_context.scan_pre_timer_low_reg = - info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG; - info->ai_context.scan_pre_timer_high_reg = - info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG; - info->ai_context.start_reg = info->me4000_regbase + ME4000_AI_START_REG; - info->ai_context.irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ai_context.sample_counter_reg = - info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG; - - return 0; -} - -static int init_dio_context(struct comedi_device *dev) -{ - - CALL_PDEBUG("In init_dio_context()\n"); - - info->dio_context.dir_reg = info->me4000_regbase + ME4000_DIO_DIR_REG; - info->dio_context.ctrl_reg = info->me4000_regbase + ME4000_DIO_CTRL_REG; - info->dio_context.port_0_reg = - info->me4000_regbase + ME4000_DIO_PORT_0_REG; - info->dio_context.port_1_reg = - info->me4000_regbase + ME4000_DIO_PORT_1_REG; - info->dio_context.port_2_reg = - info->me4000_regbase + ME4000_DIO_PORT_2_REG; - info->dio_context.port_3_reg = - info->me4000_regbase + ME4000_DIO_PORT_3_REG; - - return 0; -} - -static int init_cnt_context(struct comedi_device *dev) -{ - - CALL_PDEBUG("In init_cnt_context()\n"); - - info->cnt_context.ctrl_reg = info->timer_regbase + ME4000_CNT_CTRL_REG; - info->cnt_context.counter_0_reg = - info->timer_regbase + ME4000_CNT_COUNTER_0_REG; - info->cnt_context.counter_1_reg = - info->timer_regbase + ME4000_CNT_COUNTER_1_REG; - info->cnt_context.counter_2_reg = - info->timer_regbase + ME4000_CNT_COUNTER_2_REG; - - return 0; -} +}; #define FIRMWARE_NOT_AVAILABLE 1 #if FIRMWARE_NOT_AVAILABLE @@ -778,12 +343,17 @@ extern unsigned char *xilinx_firm; static int xilinx_download(struct comedi_device *dev) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct me4000_info *info = dev->private; + unsigned long xilinx_iobase = pci_resource_start(pcidev, 5); u32 value = 0; wait_queue_head_t queue; int idx = 0; int size = 0; + unsigned int intcsr; - CALL_PDEBUG("In xilinx_download()\n"); + if (!xilinx_iobase) + return -ENODEV; init_waitqueue_head(&queue); @@ -791,32 +361,31 @@ static int xilinx_download(struct comedi_device *dev) * Set PLX local interrupt 2 polarity to high. * Interrupt is thrown by init pin of xilinx. */ - outl(0x10, info->plx_regbase + PLX_INTCSR); + outl(PLX9052_INTCSR_LI2POL, info->plx_regbase + PLX9052_INTCSR); /* Set /CS and /WRITE of the Xilinx */ - value = inl(info->plx_regbase + PLX_ICR); - value |= 0x100; - outl(value, info->plx_regbase + PLX_ICR); + value = inl(info->plx_regbase + PLX9052_CNTRL); + value |= PLX9052_CNTRL_UIO2_DATA; + outl(value, info->plx_regbase + PLX9052_CNTRL); /* Init Xilinx with CS1 */ - inb(info->program_regbase + 0xC8); + inb(xilinx_iobase + 0xC8); /* Wait until /INIT pin is set */ udelay(20); - if (!(inl(info->plx_regbase + PLX_INTCSR) & 0x20)) { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Can't init Xilinx\n", dev->minor); + intcsr = inl(info->plx_regbase + PLX9052_INTCSR); + if (!(intcsr & PLX9052_INTCSR_LI2STAT)) { + dev_err(dev->class_dev, "Can't init Xilinx\n"); return -EIO; } /* Reset /CS and /WRITE of the Xilinx */ - value = inl(info->plx_regbase + PLX_ICR); - value &= ~0x100; - outl(value, info->plx_regbase + PLX_ICR); + value = inl(info->plx_regbase + PLX9052_CNTRL); + value &= ~PLX9052_CNTRL_UIO2_DATA; + outl(value, info->plx_regbase + PLX9052_CNTRL); if (FIRMWARE_NOT_AVAILABLE) { - comedi_error(dev, "xilinx firmware unavailable " - "due to licensing, aborting"); + dev_err(dev->class_dev, + "xilinx firmware unavailable due to licensing, aborting"); return -EIO; } else { /* Download Xilinx firmware */ @@ -825,115 +394,76 @@ static int xilinx_download(struct comedi_device *dev) udelay(10); for (idx = 0; idx < size; idx++) { - outb(xilinx_firm[16 + idx], info->program_regbase); + outb(xilinx_firm[16 + idx], xilinx_iobase); udelay(10); /* Check if BUSY flag is low */ - if (inl(info->plx_regbase + PLX_ICR) & 0x20) { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Xilinx is still busy (idx = %d)\n", - dev->minor, idx); + if (inl(info->plx_regbase + PLX9052_CNTRL) & PLX9052_CNTRL_UIO1_DATA) { + dev_err(dev->class_dev, + "Xilinx is still busy (idx = %d)\n", + idx); return -EIO; } } } /* If done flag is high download was successful */ - if (inl(info->plx_regbase + PLX_ICR) & 0x4) { + if (inl(info->plx_regbase + PLX9052_CNTRL) & PLX9052_CNTRL_UIO0_DATA) { } else { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "DONE flag is not set\n", dev->minor); - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Download not successful\n", dev->minor); + dev_err(dev->class_dev, "DONE flag is not set\n"); + dev_err(dev->class_dev, "Download not successful\n"); return -EIO; } /* Set /CS and /WRITE */ - value = inl(info->plx_regbase + PLX_ICR); - value |= 0x100; - outl(value, info->plx_regbase + PLX_ICR); + value = inl(info->plx_regbase + PLX9052_CNTRL); + value |= PLX9052_CNTRL_UIO2_DATA; + outl(value, info->plx_regbase + PLX9052_CNTRL); return 0; } -static int reset_board(struct comedi_device *dev) +static void me4000_reset(struct comedi_device *dev) { - unsigned long icr; - - CALL_PDEBUG("In reset_board()\n"); + struct me4000_info *info = dev->private; + unsigned int val; + int chan; /* Make a hardware reset */ - icr = me4000_inl(dev, info->plx_regbase + PLX_ICR); - icr |= 0x40000000; - me4000_outl(dev, icr, info->plx_regbase + PLX_ICR); - icr &= ~0x40000000; - me4000_outl(dev, icr, info->plx_regbase + PLX_ICR); + val = inl(info->plx_regbase + PLX9052_CNTRL); + val |= PLX9052_CNTRL_PCI_RESET; + outl(val, info->plx_regbase + PLX9052_CNTRL); + val &= ~PLX9052_CNTRL_PCI_RESET; + outl(val , info->plx_regbase + PLX9052_CNTRL); /* 0x8000 to the DACs means an output voltage of 0V */ - me4000_outl(dev, 0x8000, - info->me4000_regbase + ME4000_AO_00_SINGLE_REG); - me4000_outl(dev, 0x8000, - info->me4000_regbase + ME4000_AO_01_SINGLE_REG); - me4000_outl(dev, 0x8000, - info->me4000_regbase + ME4000_AO_02_SINGLE_REG); - me4000_outl(dev, 0x8000, - info->me4000_regbase + ME4000_AO_03_SINGLE_REG); + for (chan = 0; chan < 4; chan++) + outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan)); /* Set both stop bits in the analog input control register */ - me4000_outl(dev, - ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AI_CTRL_REG); + outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, + dev->iobase + ME4000_AI_CTRL_REG); /* Set both stop bits in the analog output control register */ - me4000_outl(dev, - ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_00_CTRL_REG); - me4000_outl(dev, - ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_01_CTRL_REG); - me4000_outl(dev, - ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_02_CTRL_REG); - me4000_outl(dev, - ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_03_CTRL_REG); + val = ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP; + for (chan = 0; chan < 4; chan++) + outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Enable interrupts on the PLX */ - me4000_outl(dev, 0x43, info->plx_regbase + PLX_INTCSR); + outl(PLX9052_INTCSR_LI1ENAB | + PLX9052_INTCSR_LI1POL | + PLX9052_INTCSR_PCIENAB, info->plx_regbase + PLX9052_INTCSR); /* Set the adustment register for AO demux */ - me4000_outl(dev, ME4000_AO_DEMUX_ADJUST_VALUE, - info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG); + outl(ME4000_AO_DEMUX_ADJUST_VALUE, + dev->iobase + ME4000_AO_DEMUX_ADJUST_REG); /* * Set digital I/O direction for port 0 * to output on isolated versions */ - if (!(me4000_inl(dev, info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) { - me4000_outl(dev, 0x1, - info->me4000_regbase + ME4000_DIO_CTRL_REG); - } - - return 0; -} - -static int me4000_detach(struct comedi_device *dev) -{ - CALL_PDEBUG("In me4000_detach()\n"); - - if (info) { - if (info->pci_dev_p) { - reset_board(dev); - if (info->plx_regbase) - comedi_pci_disable(info->pci_dev_p); - pci_dev_put(info->pci_dev_p); - } - } - - return 0; + if (!(inl(dev->iobase + ME4000_DIO_DIR_REG) & 0x1)) + outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG); } /*============================================================================= @@ -944,23 +474,20 @@ 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); int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); - unsigned long entry = 0; - unsigned long tmp; - long lval; - - CALL_PDEBUG("In me4000_ai_insn_read()\n"); + unsigned int entry = 0; + unsigned int tmp; + unsigned int lval; if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid instruction length %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } @@ -978,19 +505,16 @@ static int me4000_ai_insn_read(struct comedi_device *dev, entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid range specified\n", dev->minor); + dev_err(dev->class_dev, "Invalid range specified\n"); return -EINVAL; } switch (aref) { case AREF_GROUND: case AREF_COMMON: - if (chan >= thisboard->ai.count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Analog input is not available\n", dev->minor); + if (chan >= thisboard->ai_nchan) { + dev_err(dev->class_dev, + "Analog input is not available\n"); return -EINVAL; } entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan; @@ -998,70 +522,61 @@ static int me4000_ai_insn_read(struct comedi_device *dev, case AREF_DIFF: if (rang == 0 || rang == 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Range must be bipolar when aref = diff\n", - dev->minor); + dev_err(dev->class_dev, + "Range must be bipolar when aref = diff\n"); return -EINVAL; } - if (chan >= thisboard->ai.diff_count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Analog input is not available\n", dev->minor); + if (chan >= thisboard->ai_diff_nchan) { + dev_err(dev->class_dev, + "Analog input is not available\n"); return -EINVAL; } entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid aref specified\n", dev->minor); + dev_err(dev->class_dev, "Invalid aref specified\n"); return -EINVAL; } entry |= ME4000_AI_LIST_LAST_ENTRY; /* Clear channel list, data fifo and both stop bits */ - tmp = me4000_inl(dev, info->ai_context.ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO | ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); - me4000_outl(dev, tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Set the acquisition mode to single */ tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 | ME4000_AI_CTRL_BIT_MODE_2); - me4000_outl(dev, tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Enable channel list and data fifo */ tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO; - me4000_outl(dev, tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Generate channel list entry */ - me4000_outl(dev, entry, info->ai_context.channel_list_reg); + outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); /* Set the timer to maximum sample rate */ - me4000_outl(dev, ME4000_AI_MIN_TICKS, info->ai_context.chan_timer_reg); - me4000_outl(dev, ME4000_AI_MIN_TICKS, - info->ai_context.chan_pre_timer_reg); + outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG); + outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); /* Start conversion by dummy read */ - me4000_inl(dev, info->ai_context.start_reg); + inl(dev->iobase + ME4000_AI_START_REG); /* Wait until ready */ udelay(10); - if (! - (me4000_inl(dev, info->ai_context.status_reg) & + if (!(inl(dev->iobase + ME4000_AI_STATUS_REG) & ME4000_AI_STATUS_BIT_EF_DATA)) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Value not available after wait\n", dev->minor); + dev_err(dev->class_dev, "Value not available after wait\n"); return -EIO; } /* Read value from data fifo */ - lval = me4000_inl(dev, info->ai_context.data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; data[0] = lval ^ 0x8000; return 1; @@ -1070,97 +585,49 @@ static int me4000_ai_insn_read(struct comedi_device *dev, static int me4000_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned long tmp; - - CALL_PDEBUG("In me4000_ai_cancel()\n"); + unsigned int tmp; /* Stop any running conversion */ - tmp = me4000_inl(dev, info->ai_context.ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); - me4000_outl(dev, tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Clear the control register */ - me4000_outl(dev, 0x0, info->ai_context.ctrl_reg); + outl(0x0, dev->iobase + ME4000_AI_CTRL_REG); return 0; } -static int ai_check_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int me4000_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - int aref; + const struct me4000_board *board = comedi_board(dev); + unsigned int max_diff_chan = board->ai_diff_nchan; + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; - CALL_PDEBUG("In ai_check_chanlist()\n"); - - /* Check whether a channel list is available */ - if (!cmd->chanlist_len) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "No channel list available\n", dev->minor); - return -EINVAL; - } - - /* Check the channel list size */ - if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Channel list is to large\n", dev->minor); - return -EINVAL; - } - - /* Check the pointer */ - if (!cmd->chanlist) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "NULL pointer to channel list\n", dev->minor); - return -EFAULT; - } - - /* Check whether aref is equal for all entries */ - aref = CR_AREF(cmd->chanlist[0]); for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_AREF(cmd->chanlist[i]) != aref) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Mode is not equal for all entries\n", - dev->minor); + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); + + if (aref != aref0) { + dev_dbg(dev->class_dev, + "Mode is not equal for all entries\n"); return -EINVAL; } - } - /* Check whether channels are available for this ending */ - if (aref == SDF_DIFF) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) >= - thisboard->ai.diff_count) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist():" - " Channel number to high\n", dev->minor); - return -EINVAL; - } - } - } else { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai.count) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Channel number to high\n", dev->minor); + if (aref == SDF_DIFF) { + if (chan >= max_diff_chan) { + dev_dbg(dev->class_dev, + "Channel number to high\n"); return -EINVAL; } - } - } - /* Check if bipolar is set for all entries when in differential mode */ - if (aref == SDF_DIFF) { - for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_RANGE(cmd->chanlist[i]) != 1 && - CR_RANGE(cmd->chanlist[i]) != 2) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Bipolar is not selected in " - "differential mode\n", - dev->minor); + if (!comedi_range_is_bipolar(s, range)) { + dev_dbg(dev->class_dev, + "Bipolar is not selected in differential mode\n"); return -EINVAL; } } @@ -1178,25 +645,18 @@ static int ai_round_cmd_args(struct comedi_device *dev, int rest; - CALL_PDEBUG("In ai_round_cmd_args()\n"); - *init_ticks = 0; *scan_ticks = 0; *chan_ticks = 0; - PDEBUG("ai_round_cmd_arg(): start_arg = %d\n", cmd->start_arg); - PDEBUG("ai_round_cmd_arg(): scan_begin_arg = %d\n", - cmd->scan_begin_arg); - PDEBUG("ai_round_cmd_arg(): convert_arg = %d\n", cmd->convert_arg); - if (cmd->start_arg) { *init_ticks = (cmd->start_arg * 33) / 1000; rest = (cmd->start_arg * 33) % 1000; - if (cmd->flags & TRIG_ROUND_NEAREST) { + if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) { if (rest > 33) (*init_ticks)++; - } else if (cmd->flags & TRIG_ROUND_UP) { + } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) { if (rest) (*init_ticks)++; } @@ -1206,10 +666,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_NEAREST) { + if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) { if (rest > 33) (*scan_ticks)++; - } else if (cmd->flags & TRIG_ROUND_UP) { + } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) { if (rest) (*scan_ticks)++; } @@ -1219,19 +679,15 @@ 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_NEAREST) { + if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_NEAREST) { if (rest > 33) (*chan_ticks)++; - } else if (cmd->flags & TRIG_ROUND_UP) { + } else if ((cmd->flags & TRIG_ROUND_MASK) == TRIG_ROUND_UP) { if (rest) (*chan_ticks)++; } } - PDEBUG("ai_round_cmd_args(): init_ticks = %d\n", *init_ticks); - PDEBUG("ai_round_cmd_args(): scan_ticks = %d\n", *scan_ticks); - PDEBUG("ai_round_cmd_args(): chan_ticks = %d\n", *chan_ticks); - return 0; } @@ -1239,21 +695,52 @@ static void ai_write_timer(struct comedi_device *dev, unsigned int init_ticks, unsigned int scan_ticks, unsigned int chan_ticks) { + outl(init_ticks - 1, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG); + outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG); - CALL_PDEBUG("In ai_write_timer()\n"); + if (scan_ticks) { + outl(scan_ticks - 1, dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG); + outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG); + } - me4000_outl(dev, init_ticks - 1, - info->ai_context.scan_pre_timer_low_reg); - me4000_outl(dev, 0x0, info->ai_context.scan_pre_timer_high_reg); + outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); + outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG); +} - if (scan_ticks) { - me4000_outl(dev, scan_ticks - 1, - info->ai_context.scan_timer_low_reg); - me4000_outl(dev, 0x0, info->ai_context.scan_timer_high_reg); +static int ai_write_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) +{ + unsigned int entry; + unsigned int chan; + unsigned int rang; + unsigned int aref; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + chan = CR_CHAN(cmd->chanlist[i]); + rang = CR_RANGE(cmd->chanlist[i]); + aref = CR_AREF(cmd->chanlist[i]); + + entry = chan; + + if (rang == 0) + entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; + else if (rang == 1) + entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; + else if (rang == 2) + entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; + else + entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; + + if (aref == SDF_DIFF) + entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; + else + entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; + + outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); } - me4000_outl(dev, chan_ticks - 1, info->ai_context.chan_pre_timer_reg); - me4000_outl(dev, chan_ticks - 1, info->ai_context.chan_timer_reg); + return 0; } static int ai_prepare(struct comedi_device *dev, @@ -1263,15 +750,13 @@ static int ai_prepare(struct comedi_device *dev, unsigned int scan_ticks, unsigned int chan_ticks) { - unsigned long tmp = 0; - - CALL_PDEBUG("In ai_prepare()\n"); + unsigned int tmp = 0; /* Write timer arguments */ ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks); /* Reset control register */ - me4000_outl(dev, tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Start sources */ if ((cmd->start_src == TRIG_EXT && @@ -1304,20 +789,20 @@ static int ai_prepare(struct comedi_device *dev, /* Stop triggers */ if (cmd->stop_src == TRIG_COUNT) { - me4000_outl(dev, cmd->chanlist_len * cmd->stop_arg, - info->ai_context.sample_counter_reg); + outl(cmd->chanlist_len * cmd->stop_arg, + dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; } else if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_COUNT) { - me4000_outl(dev, cmd->scan_end_arg, - info->ai_context.sample_counter_reg); + outl(cmd->scan_end_arg, + dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; } else { tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; } /* Write the setup to the control register */ - me4000_outl(dev, tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Write the channel list */ ai_write_chanlist(dev, s, cmd); @@ -1325,44 +810,6 @@ static int ai_prepare(struct comedi_device *dev, return 0; } -static int ai_write_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - unsigned int entry; - unsigned int chan; - unsigned int rang; - unsigned int aref; - int i; - - CALL_PDEBUG("In ai_write_chanlist()\n"); - - for (i = 0; i < cmd->chanlist_len; i++) { - chan = CR_CHAN(cmd->chanlist[i]); - rang = CR_RANGE(cmd->chanlist[i]); - aref = CR_AREF(cmd->chanlist[i]); - - entry = chan; - - if (rang == 0) - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; - else if (rang == 1) - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; - else if (rang == 2) - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; - else - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; - - if (aref == SDF_DIFF) - entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; - else - entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; - - me4000_outl(dev, entry, info->ai_context.channel_list_reg); - } - - return 0; -} - static int me4000_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1372,8 +819,6 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, unsigned int chan_ticks = 0; struct comedi_cmd *cmd = &s->async->cmd; - CALL_PDEBUG("In me4000_ai_do_cmd()\n"); - /* Reset the analog input */ err = me4000_ai_cancel(dev, s); if (err) @@ -1391,23 +836,11 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, return err; /* Start acquistion by dummy read */ - me4000_inl(dev, info->ai_context.start_reg); + inl(dev->iobase + ME4000_AI_START_REG); return 0; } -/* - * me4000_ai_do_cmd_test(): - * - * The demo cmd.c in ./comedilib/demo specifies 6 return values: - * - success - * - invalid source - * - source conflict - * - invalid argument - * - argument conflict - * - invalid chanlist - * So I tried to adopt this scheme. - */ static int me4000_ai_do_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -1418,125 +851,35 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, unsigned int scan_ticks; int err = 0; - CALL_PDEBUG("In me4000_ai_do_cmd_test()\n"); - - PDEBUG("me4000_ai_do_cmd_test(): subdev = %d\n", cmd->subdev); - PDEBUG("me4000_ai_do_cmd_test(): flags = %08X\n", cmd->flags); - PDEBUG("me4000_ai_do_cmd_test(): start_src = %08X\n", - cmd->start_src); - PDEBUG("me4000_ai_do_cmd_test(): start_arg = %d\n", - cmd->start_arg); - PDEBUG("me4000_ai_do_cmd_test(): scan_begin_src = %08X\n", - cmd->scan_begin_src); - PDEBUG("me4000_ai_do_cmd_test(): scan_begin_arg = %d\n", - cmd->scan_begin_arg); - PDEBUG("me4000_ai_do_cmd_test(): convert_src = %08X\n", - cmd->convert_src); - PDEBUG("me4000_ai_do_cmd_test(): convert_arg = %d\n", - cmd->convert_arg); - PDEBUG("me4000_ai_do_cmd_test(): scan_end_src = %08X\n", - cmd->scan_end_src); - PDEBUG("me4000_ai_do_cmd_test(): scan_end_arg = %d\n", - cmd->scan_end_arg); - PDEBUG("me4000_ai_do_cmd_test(): stop_src = %08X\n", - cmd->stop_src); - PDEBUG("me4000_ai_do_cmd_test(): stop_arg = %d\n", cmd->stop_arg); - PDEBUG("me4000_ai_do_cmd_test(): chanlist = %d\n", - (unsigned int)cmd->chanlist); - PDEBUG("me4000_ai_do_cmd_test(): chanlist_len = %d\n", - cmd->chanlist_len); - /* Only rounding flags are implemented */ cmd->flags &= TRIG_ROUND_NEAREST | TRIG_ROUND_UP | TRIG_ROUND_DOWN; /* Round the timer arguments */ ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks); - /* - * Stage 1. Check if the trigger sources are generally valid. - */ - switch (cmd->start_src) { - case TRIG_NOW: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->start_src &= TRIG_NOW | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start source\n", dev->minor); - cmd->start_src = TRIG_NOW; - err++; - } - switch (cmd->scan_begin_src) { - case TRIG_FOLLOW: - case TRIG_TIMER: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan begin source\n", dev->minor); - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } - switch (cmd->convert_src) { - case TRIG_TIMER: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert source\n", dev->minor); - cmd->convert_src = TRIG_TIMER; - err++; - } - switch (cmd->scan_end_src) { - case TRIG_NONE: - case TRIG_COUNT: - break; - case TRIG_ANY: - cmd->scan_end_src &= TRIG_NONE | TRIG_COUNT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end source\n", dev->minor); - cmd->scan_end_src = TRIG_NONE; - err++; - } - switch (cmd->stop_src) { - case TRIG_NONE: - case TRIG_COUNT: - break; - case TRIG_ANY: - cmd->stop_src &= TRIG_NONE | TRIG_COUNT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop source\n", dev->minor); - cmd->stop_src = TRIG_NONE; - err++; - } + /* 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_FOLLOW | 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_NONE | TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE | TRIG_COUNT); + if (err) return 1; - /* - * Stage 2. Check for trigger source conflicts. - */ + /* 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->scan_end_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + if (cmd->start_src == TRIG_NOW && cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER) { @@ -1556,63 +899,31 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_EXT) { } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start trigger combination\n", dev->minor); - cmd->start_src = TRIG_NOW; - cmd->scan_begin_src = TRIG_FOLLOW; - cmd->convert_src = TRIG_TIMER; - err++; + err |= -EINVAL; } - if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) { - } else if (cmd->stop_src == TRIG_COUNT && - cmd->scan_end_src == TRIG_NONE) { - } else if (cmd->stop_src == TRIG_NONE && - cmd->scan_end_src == TRIG_COUNT) { - } else if (cmd->stop_src == TRIG_COUNT && - cmd->scan_end_src == TRIG_COUNT) { - } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop trigger combination\n", dev->minor); - cmd->stop_src = TRIG_NONE; - cmd->scan_end_src = TRIG_NONE; - err++; - } if (err) return 2; - /* - * Stage 3. Check if arguments are generally valid. - */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + if (cmd->chanlist_len < 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "No channel list\n", dev->minor); cmd->chanlist_len = 1; - err++; + err |= -EINVAL; } if (init_ticks < 66) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Start arg to low\n", dev->minor); cmd->start_arg = 2000; - err++; + err |= -EINVAL; } if (scan_ticks && scan_ticks < 67) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Scan begin arg to low\n", dev->minor); cmd->scan_begin_arg = 2031; - err++; + err |= -EINVAL; } if (chan_ticks < 66) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Convert arg to low\n", dev->minor); cmd->convert_arg = 2000; - err++; + err |= -EINVAL; } if (err) @@ -1627,23 +938,17 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } if (scan_ticks <= cmd->chanlist_len * chan_ticks) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); /* At least one tick more */ cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; @@ -1655,16 +960,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1674,23 +975,17 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } if (scan_ticks <= cmd->chanlist_len * chan_ticks) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); /* At least one tick more */ cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; @@ -1702,16 +997,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1721,16 +1012,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1740,27 +1027,21 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } } if (cmd->stop_src == TRIG_COUNT) { if (cmd->stop_arg == 0) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop arg\n", dev->minor); + 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) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); cmd->scan_end_arg = 1; err++; } @@ -1769,10 +1050,11 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, if (err) return 4; - /* - * Stage 5. Check the channel list. - */ - if (ai_check_chanlist(dev, s, cmd)) + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= me4000_ai_check_chanlist(dev, s, cmd); + + if (err) return 5; return 0; @@ -1782,43 +1064,22 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) { unsigned int tmp; struct comedi_device *dev = dev_id; - struct comedi_subdevice *s = dev->subdevices; - struct me4000_ai_context *ai_context = &info->ai_context; + struct comedi_subdevice *s = dev->read_subdev; int i; int c = 0; - long lval; - - ISR_PDEBUG("me4000_ai_isr() is executed\n"); + unsigned int lval; - if (!dev->attached) { - ISR_PDEBUG("me4000_ai_isr() premature interrupt\n"); + if (!dev->attached) return IRQ_NONE; - } - - /* Reset all events */ - s->async->events = 0; - /* Check if irq number is right */ - if (irq != ai_context->irq) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Incorrect interrupt num: %d\n", dev->minor, irq); - return IRQ_HANDLED; - } - - if (me4000_inl(dev, - ai_context->irq_status_reg) & + if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_AI_HF) { - ISR_PDEBUG - ("me4000_ai_isr(): Fifo half full interrupt occurred\n"); - /* Read status register to find out what happened */ - tmp = me4000_inl(dev, ai_context->ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { - ISR_PDEBUG("me4000_ai_isr(): Fifo full\n"); c = ME4000_AI_FIFO_COUNT; /* @@ -1828,25 +1089,20 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - me4000_outl(dev, tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "FIFO overflow\n", dev->minor); + dev_err(dev->class_dev, "FIFO overflow\n"); } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { - ISR_PDEBUG("me4000_ai_isr(): Fifo half full\n"); - s->async->events |= COMEDI_CB_BLOCK; c = ME4000_AI_FIFO_COUNT / 2; } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Can't determine state of fifo\n", dev->minor); + dev_err(dev->class_dev, + "Can't determine state of fifo\n"); c = 0; /* @@ -1856,23 +1112,19 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - me4000_outl(dev, tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Undefined FIFO state\n", dev->minor); + dev_err(dev->class_dev, "Undefined FIFO state\n"); } - ISR_PDEBUG("me4000_ai_isr(): Try to read %d values\n", c); - for (i = 0; i < c; i++) { /* Read value from data fifo */ - lval = inl(ai_context->data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; - if (!comedi_buf_put(s->async, lval)) { + if (!comedi_buf_put(s, lval)) { /* * Buffer overflow, so stop conversion * and disable all interrupts @@ -1880,68 +1132,57 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - me4000_outl(dev, tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_OVERFLOW; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Buffer overflow\n", dev->minor); + dev_err(dev->class_dev, "Buffer overflow\n"); break; } } /* Work is done, so reset the interrupt */ - ISR_PDEBUG("me4000_ai_isr(): Reset fifo half full interrupt\n"); tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET; - me4000_outl(dev, tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET; - me4000_outl(dev, tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } - if (me4000_inl(dev, - ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) { - ISR_PDEBUG - ("me4000_ai_isr(): Sample counter interrupt occurred\n"); - + if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & + ME4000_IRQ_STATUS_BIT_SC) { s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA; /* * Acquisition is complete, so stop * conversion and disable all interrupts */ - tmp = me4000_inl(dev, ai_context->ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - me4000_outl(dev, tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Poll data until fifo empty */ - while (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_EF_DATA) { + while (inl(dev->iobase + ME4000_AI_CTRL_REG) & + ME4000_AI_STATUS_BIT_EF_DATA) { /* Read value from data fifo */ - lval = inl(ai_context->data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; - if (!comedi_buf_put(s->async, lval)) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Buffer overflow\n", dev->minor); + if (!comedi_buf_put(s, lval)) { + dev_err(dev->class_dev, "Buffer overflow\n"); s->async->events |= COMEDI_CB_OVERFLOW; break; } } /* Work is done, so reset the interrupt */ - ISR_PDEBUG - ("me4000_ai_isr(): Reset interrupt from sample counter\n"); tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET; - me4000_outl(dev, tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET; - me4000_outl(dev, tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } - ISR_PDEBUG("me4000_ai_isr(): Events = 0x%X\n", s->async->events); - if (s->async->events) comedi_event(dev, s); @@ -1956,57 +1197,49 @@ static int me4000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, 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 long tmp; - - CALL_PDEBUG("In me4000_ao_insn_write()\n"); + unsigned int tmp; if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid instruction length %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - if (chan >= thisboard->ao.count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid channel %d\n", dev->minor, insn->n); + if (chan >= thisboard->ao_nchan) { + dev_err(dev->class_dev, "Invalid channel %d\n", insn->n); return -EINVAL; } if (rang != 0) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid range %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid range %d\n", insn->n); return -EINVAL; } if (aref != AREF_GROUND && aref != AREF_COMMON) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid aref %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid aref %d\n", insn->n); return -EINVAL; } /* Stop any running conversion */ - tmp = me4000_inl(dev, info->ao_context[chan].ctrl_reg); + tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan)); tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; - me4000_outl(dev, tmp, info->ao_context[chan].ctrl_reg); + outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Clear control register and set to single mode */ - me4000_outl(dev, 0x0, info->ao_context[chan].ctrl_reg); + outl(0x0, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Write data value */ - me4000_outl(dev, data[0], info->ao_context[chan].single_reg); + outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan)); /* Store in the mirror */ - info->ao_context[chan].mirror = data[0]; + info->ao_readback[chan] = data[0]; return 1; } @@ -2015,356 +1248,156 @@ 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) { - printk - ("comedi%d: me4000: me4000_ao_insn_read(): " - "Invalid instruction length\n", dev->minor); + dev_err(dev->class_dev, "Invalid instruction length\n"); return -EINVAL; } - data[0] = info->ao_context[chan].mirror; + data[0] = info->ao_readback[chan]; return 1; } -/*============================================================================= - Digital I/O section - ===========================================================================*/ - static int me4000_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - - CALL_PDEBUG("In me4000_dio_insn_bits()\n"); - - /* Length of data must be 2 (mask and new data, see below) */ - if (insn->n == 0) - return 0; - - if (insn->n != 2) { - printk - ("comedi%d: me4000: me4000_dio_insn_bits(): " - "Invalid instruction length\n", dev->minor); - return -EINVAL; - } - - /* - * The insn data consists of a mask in data[0] and the new data - * in data[1]. The mask defines which bits we are concerning about. - * The new data must be anded with the mask. - * Each channel corresponds to a bit. - */ - if (data[0]) { - /* Check if requested ports are configured for output */ - if ((s->io_bits & data[0]) != data[0]) - return -EIO; - - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - - /* Write out the new digital output lines */ - me4000_outl(dev, (s->state >> 0) & 0xFF, - info->dio_context.port_0_reg); - me4000_outl(dev, (s->state >> 8) & 0xFF, - info->dio_context.port_1_reg); - me4000_outl(dev, (s->state >> 16) & 0xFF, - info->dio_context.port_2_reg); - me4000_outl(dev, (s->state >> 24) & 0xFF, - info->dio_context.port_3_reg); - } - - /* On return, data[1] contains the value of - the digital input and output lines. */ - data[1] = - ((me4000_inl(dev, info->dio_context.port_0_reg) & 0xFF) << 0) | - ((me4000_inl(dev, info->dio_context.port_1_reg) & 0xFF) << 8) | - ((me4000_inl(dev, info->dio_context.port_2_reg) & 0xFF) << 16) | - ((me4000_inl(dev, info->dio_context.port_3_reg) & 0xFF) << 24); - - return 2; + if (comedi_dio_update_state(s, data)) { + outl((s->state >> 0) & 0xFF, + dev->iobase + ME4000_DIO_PORT_0_REG); + outl((s->state >> 8) & 0xFF, + dev->iobase + ME4000_DIO_PORT_1_REG); + outl((s->state >> 16) & 0xFF, + dev->iobase + ME4000_DIO_PORT_2_REG); + outl((s->state >> 24) & 0xFF, + dev->iobase + ME4000_DIO_PORT_3_REG); + } + + data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) | + ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) | + ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) | + ((inl(dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24); + + return insn->n; } static int me4000_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned long tmp; - int chan = CR_CHAN(insn->chanspec); - - CALL_PDEBUG("In me4000_dio_insn_config()\n"); - - if (data[0] == INSN_CONFIG_DIO_QUERY) { - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - } + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + unsigned int tmp; + int ret; + + if (chan < 8) + mask = 0x000000ff; + else if (chan < 16) + mask = 0x0000ff00; + else if (chan < 24) + mask = 0x00ff0000; + else + mask = 0xff000000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG); + tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | ME4000_DIO_CTRL_BIT_MODE_1 | + ME4000_DIO_CTRL_BIT_MODE_2 | ME4000_DIO_CTRL_BIT_MODE_3 | + ME4000_DIO_CTRL_BIT_MODE_4 | ME4000_DIO_CTRL_BIT_MODE_5 | + ME4000_DIO_CTRL_BIT_MODE_6 | ME4000_DIO_CTRL_BIT_MODE_7); + if (s->io_bits & 0x000000ff) + tmp |= ME4000_DIO_CTRL_BIT_MODE_0; + if (s->io_bits & 0x0000ff00) + tmp |= ME4000_DIO_CTRL_BIT_MODE_2; + if (s->io_bits & 0x00ff0000) + tmp |= ME4000_DIO_CTRL_BIT_MODE_4; + if (s->io_bits & 0xff000000) + tmp |= ME4000_DIO_CTRL_BIT_MODE_6; /* - * The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. - * On the ME-4000 it is only possible to switch port wise (8 bit) + * Check for optoisolated ME-4000 version. + * If one the first port is a fixed output + * port and the second is a fixed input port. */ - - tmp = me4000_inl(dev, info->dio_context.ctrl_reg); - - if (data[0] == COMEDI_OUTPUT) { - if (chan < 8) { - s->io_bits |= 0xFF; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | - ME4000_DIO_CTRL_BIT_MODE_1); - tmp |= ME4000_DIO_CTRL_BIT_MODE_0; - } else if (chan < 16) { - /* - * Chech for optoisolated ME-4000 version. - * If one the first port is a fixed output - * port and the second is a fixed input port. - */ - if (!me4000_inl(dev, info->dio_context.dir_reg)) - return -ENODEV; - - s->io_bits |= 0xFF00; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | - ME4000_DIO_CTRL_BIT_MODE_3); - tmp |= ME4000_DIO_CTRL_BIT_MODE_2; - } else if (chan < 24) { - s->io_bits |= 0xFF0000; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 | - ME4000_DIO_CTRL_BIT_MODE_5); - tmp |= ME4000_DIO_CTRL_BIT_MODE_4; - } else if (chan < 32) { - s->io_bits |= 0xFF000000; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 | - ME4000_DIO_CTRL_BIT_MODE_7); - tmp |= ME4000_DIO_CTRL_BIT_MODE_6; - } else { - return -EINVAL; - } - } else { - if (chan < 8) { - /* - * Chech for optoisolated ME-4000 version. - * If one the first port is a fixed output - * port and the second is a fixed input port. - */ - if (!me4000_inl(dev, info->dio_context.dir_reg)) - return -ENODEV; - - s->io_bits &= ~0xFF; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | - ME4000_DIO_CTRL_BIT_MODE_1); - } else if (chan < 16) { - s->io_bits &= ~0xFF00; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | - ME4000_DIO_CTRL_BIT_MODE_3); - } else if (chan < 24) { - s->io_bits &= ~0xFF0000; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_4 | - ME4000_DIO_CTRL_BIT_MODE_5); - } else if (chan < 32) { - s->io_bits &= ~0xFF000000; - tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_6 | - ME4000_DIO_CTRL_BIT_MODE_7); - } else { - return -EINVAL; - } + if (inl(dev->iobase + ME4000_DIO_DIR_REG)) { + s->io_bits |= 0x000000ff; + s->io_bits &= ~0x0000ff00; + tmp |= ME4000_DIO_CTRL_BIT_MODE_0; + tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_2 | + ME4000_DIO_CTRL_BIT_MODE_3); } - me4000_outl(dev, tmp, info->dio_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG); - return 1; + return insn->n; } /*============================================================================= Counter section ===========================================================================*/ -static int cnt_reset(struct comedi_device *dev, unsigned int channel) -{ - - CALL_PDEBUG("In cnt_reset()\n"); - - switch (channel) { - case 0: - me4000_outb(dev, 0x30, info->cnt_context.ctrl_reg); - me4000_outb(dev, 0x00, info->cnt_context.counter_0_reg); - me4000_outb(dev, 0x00, info->cnt_context.counter_0_reg); - break; - case 1: - me4000_outb(dev, 0x70, info->cnt_context.ctrl_reg); - me4000_outb(dev, 0x00, info->cnt_context.counter_1_reg); - me4000_outb(dev, 0x00, info->cnt_context.counter_1_reg); - break; - case 2: - me4000_outb(dev, 0xB0, info->cnt_context.ctrl_reg); - me4000_outb(dev, 0x00, info->cnt_context.counter_2_reg); - me4000_outb(dev, 0x00, info->cnt_context.counter_2_reg); - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_reset(): Invalid channel\n", - dev->minor); - return -EINVAL; - } - - return 0; -} - -static int cnt_config(struct comedi_device *dev, unsigned int channel, - unsigned int mode) -{ - int tmp = 0; - - CALL_PDEBUG("In cnt_config()\n"); - - switch (channel) { - case 0: - tmp |= ME4000_CNT_COUNTER_0; - break; - case 1: - tmp |= ME4000_CNT_COUNTER_1; - break; - case 2: - tmp |= ME4000_CNT_COUNTER_2; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_config(): Invalid channel\n", - dev->minor); - return -EINVAL; - } - - switch (mode) { - case 0: - tmp |= ME4000_CNT_MODE_0; - break; - case 1: - tmp |= ME4000_CNT_MODE_1; - break; - case 2: - tmp |= ME4000_CNT_MODE_2; - break; - case 3: - tmp |= ME4000_CNT_MODE_3; - break; - case 4: - tmp |= ME4000_CNT_MODE_4; - break; - case 5: - tmp |= ME4000_CNT_MODE_5; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_config(): Invalid counter mode\n", - dev->minor); - return -EINVAL; - } - - /* Write the control word */ - tmp |= 0x30; - me4000_outb(dev, tmp, info->cnt_context.ctrl_reg); - - return 0; -} - static int me4000_cnt_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - + struct me4000_info *info = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int err; - CALL_PDEBUG("In me4000_cnt_insn_config()\n"); - switch (data[0]) { case GPCT_RESET: - if (insn->n != 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction length%d\n", - dev->minor, insn->n); + if (insn->n != 1) return -EINVAL; - } - err = cnt_reset(dev, insn->chanspec); + err = i8254_set_mode(info->timer_regbase, 0, chan, + I8254_MODE0 | I8254_BINARY); if (err) return err; + i8254_write(info->timer_regbase, 0, chan, 0); break; case GPCT_SET_OPERATION: - if (insn->n != 2) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction length%d\n", - dev->minor, insn->n); + if (insn->n != 2) return -EINVAL; - } - err = cnt_config(dev, insn->chanspec, data[1]); + err = i8254_set_mode(info->timer_regbase, 0, chan, + (data[1] << 1) | I8254_BINARY); if (err) return err; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction\n", dev->minor); return -EINVAL; } - return 2; + return insn->n; } static int me4000_cnt_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - - unsigned short tmp; - - CALL_PDEBUG("In me4000_cnt_insn_read()\n"); + struct me4000_info *info = dev->private; if (insn->n == 0) return 0; if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_read(): " - "Invalid instruction length %d\n", - dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - switch (insn->chanspec) { - case 0: - tmp = me4000_inb(dev, info->cnt_context.counter_0_reg); - data[0] = tmp; - tmp = me4000_inb(dev, info->cnt_context.counter_0_reg); - data[0] |= tmp << 8; - break; - case 1: - tmp = me4000_inb(dev, info->cnt_context.counter_1_reg); - data[0] = tmp; - tmp = me4000_inb(dev, info->cnt_context.counter_1_reg); - data[0] |= tmp << 8; - break; - case 2: - tmp = me4000_inb(dev, info->cnt_context.counter_2_reg); - data[0] = tmp; - tmp = me4000_inb(dev, info->cnt_context.counter_2_reg); - data[0] |= tmp << 8; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_read(): " - "Invalid channel %d\n", - dev->minor, insn->chanspec); - return -EINVAL; - } + data[0] = i8254_read(info->timer_regbase, 0, insn->chanspec); return 1; } @@ -2373,88 +1406,209 @@ static int me4000_cnt_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - - unsigned short tmp; - - CALL_PDEBUG("In me4000_cnt_insn_write()\n"); + struct me4000_info *info = dev->private; if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_write(): " - "Invalid instruction length %d\n", - dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - switch (insn->chanspec) { - case 0: - tmp = data[0] & 0xFF; - me4000_outb(dev, tmp, info->cnt_context.counter_0_reg); - tmp = (data[0] >> 8) & 0xFF; - me4000_outb(dev, tmp, info->cnt_context.counter_0_reg); - break; - case 1: - tmp = data[0] & 0xFF; - me4000_outb(dev, tmp, info->cnt_context.counter_1_reg); - tmp = (data[0] >> 8) & 0xFF; - me4000_outb(dev, tmp, info->cnt_context.counter_1_reg); - break; - case 2: - tmp = data[0] & 0xFF; - me4000_outb(dev, tmp, info->cnt_context.counter_2_reg); - tmp = (data[0] >> 8) & 0xFF; - me4000_outb(dev, tmp, info->cnt_context.counter_2_reg); - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_write(): " - "Invalid channel %d\n", - dev->minor, insn->chanspec); - return -EINVAL; - } + i8254_write(info->timer_regbase, 0, insn->chanspec, data[0]); return 1; } -static int __devinit driver_me4000_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static int me4000_auto_attach(struct comedi_device *dev, + unsigned long context) { - return comedi_pci_auto_config(dev, driver_me4000.driver_name); + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct me4000_board *thisboard = NULL; + struct me4000_info *info; + struct comedi_subdevice *s; + int result; + + if (context < ARRAY_SIZE(me4000_boards)) + thisboard = &me4000_boards[context]; + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; + + info = comedi_alloc_devpriv(dev, sizeof(*info)); + if (!info) + return -ENOMEM; + + result = comedi_pci_enable(dev); + if (result) + return result; + + info->plx_regbase = pci_resource_start(pcidev, 1); + dev->iobase = pci_resource_start(pcidev, 2); + info->timer_regbase = pci_resource_start(pcidev, 3); + if (!info->plx_regbase || !dev->iobase || !info->timer_regbase) + return -ENODEV; + + result = xilinx_download(dev); + if (result) + return result; + + me4000_reset(dev); + + if (pcidev->irq > 0) { + result = request_irq(pcidev->irq, me4000_ai_isr, IRQF_SHARED, + dev->board_name, dev); + if (result == 0) + dev->irq = pcidev->irq; + } + + result = comedi_alloc_subdevices(dev, 4); + if (result) + return result; + + /*========================================================================= + Analog input subdevice + ========================================================================*/ + + s = &dev->subdevices[0]; + + if (thisboard->ai_nchan) { + s->type = COMEDI_SUBD_AI; + s->subdev_flags = + SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = thisboard->ai_nchan; + s->maxdata = 0xFFFF; /* 16 bit ADC */ + s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; + s->range_table = &me4000_ai_range; + s->insn_read = me4000_ai_insn_read; + + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->cancel = me4000_ai_cancel; + s->do_cmdtest = me4000_ai_do_cmd_test; + s->do_cmd = me4000_ai_do_cmd; + } + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /*========================================================================= + Analog output subdevice + ========================================================================*/ + + s = &dev->subdevices[1]; + + if (thisboard->ao_nchan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND; + s->n_chan = thisboard->ao_nchan; + 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; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /*========================================================================= + Digital I/O subdevice + ========================================================================*/ + + s = &dev->subdevices[2]; + + if (thisboard->dio_nchan) { + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = thisboard->dio_nchan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = me4000_dio_insn_bits; + s->insn_config = me4000_dio_insn_config; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* + * Check for optoisolated ME-4000 version. If one the first + * port is a fixed output port and the second is a fixed input port. + */ + if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) { + s->io_bits |= 0xFF; + outl(ME4000_DIO_CTRL_BIT_MODE_0, + dev->iobase + ME4000_DIO_DIR_REG); + } + + /*========================================================================= + Counter subdevice + ========================================================================*/ + + s = &dev->subdevices[3]; + + if (thisboard->has_counter) { + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 3; + s->maxdata = 0xFFFF; /* 16 bit counters */ + s->insn_read = me4000_cnt_insn_read; + s->insn_write = me4000_cnt_insn_write; + s->insn_config = me4000_cnt_insn_config; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + return 0; } -static void __devexit driver_me4000_pci_remove(struct pci_dev *dev) +static void me4000_detach(struct comedi_device *dev) { - comedi_pci_auto_unconfig(dev); + if (dev->irq) + free_irq(dev->irq, dev); + if (dev->iobase) + me4000_reset(dev); + comedi_pci_disable(dev); } -static struct pci_driver driver_me4000_pci_driver = { - .id_table = me4000_pci_table, - .probe = &driver_me4000_pci_probe, - .remove = __devexit_p(&driver_me4000_pci_remove) +static struct comedi_driver me4000_driver = { + .driver_name = "me4000", + .module = THIS_MODULE, + .auto_attach = me4000_auto_attach, + .detach = me4000_detach, }; -static int __init driver_me4000_init_module(void) +static int me4000_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_me4000); - if (retval < 0) - return retval; - - driver_me4000_pci_driver.name = (char *)driver_me4000.driver_name; - return pci_register_driver(&driver_me4000_pci_driver); + return comedi_pci_auto_config(dev, &me4000_driver, id->driver_data); } -static void __exit driver_me4000_cleanup_module(void) -{ - pci_unregister_driver(&driver_me4000_pci_driver); - comedi_driver_unregister(&driver_me4000); -} +static const struct pci_device_id me4000_pci_table[] = { + { PCI_VDEVICE(MEILHAUS, 0x4650), BOARD_ME4650 }, + { PCI_VDEVICE(MEILHAUS, 0x4660), BOARD_ME4660 }, + { PCI_VDEVICE(MEILHAUS, 0x4661), BOARD_ME4660I }, + { PCI_VDEVICE(MEILHAUS, 0x4662), BOARD_ME4660S }, + { PCI_VDEVICE(MEILHAUS, 0x4663), BOARD_ME4660IS }, + { PCI_VDEVICE(MEILHAUS, 0x4670), BOARD_ME4670 }, + { PCI_VDEVICE(MEILHAUS, 0x4671), BOARD_ME4670I }, + { PCI_VDEVICE(MEILHAUS, 0x4672), BOARD_ME4670S }, + { PCI_VDEVICE(MEILHAUS, 0x4673), BOARD_ME4670IS }, + { PCI_VDEVICE(MEILHAUS, 0x4680), BOARD_ME4680 }, + { PCI_VDEVICE(MEILHAUS, 0x4681), BOARD_ME4680I }, + { PCI_VDEVICE(MEILHAUS, 0x4682), BOARD_ME4680S }, + { PCI_VDEVICE(MEILHAUS, 0x4683), BOARD_ME4680IS }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, me4000_pci_table); -module_init(driver_me4000_init_module); -module_exit(driver_me4000_cleanup_module); +static struct pci_driver me4000_pci_driver = { + .name = "me4000", + .id_table = me4000_pci_table, + .probe = me4000_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(me4000_driver, me4000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/me4000.h b/drivers/staging/comedi/drivers/me4000.h deleted file mode 100644 index 733b19243c7..00000000000 --- a/drivers/staging/comedi/drivers/me4000.h +++ /dev/null @@ -1,446 +0,0 @@ -/* - me4000.h - Register descriptions and defines for the ME-4000 board family - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998-9 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef _ME4000_H_ -#define _ME4000_H_ - -/*============================================================================= - Debug section - ===========================================================================*/ - -#undef ME4000_CALL_DEBUG /* Debug function entry and exit */ -#undef ME4000_PORT_DEBUG /* Debug port access */ -#undef ME4000_ISR_DEBUG /* Debug the interrupt service routine */ -#undef ME4000_DEBUG /* General purpose debug masseges */ - -#ifdef ME4000_CALL_DEBUG -#undef CALL_PDEBUG -#define CALL_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args) -#else -# define CALL_PDEBUG(fmt, args...) /* no debugging, do nothing */ -#endif - -#ifdef ME4000_PORT_DEBUG -#undef PORT_PDEBUG -#define PORT_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args) -#else -#define PORT_PDEBUG(fmt, args...) /* no debugging, do nothing */ -#endif - -#ifdef ME4000_ISR_DEBUG -#undef ISR_PDEBUG -#define ISR_PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args) -#else -#define ISR_PDEBUG(fmt, args...) /* no debugging, do nothing */ -#endif - -#ifdef ME4000_DEBUG -#undef PDEBUG -#define PDEBUG(fmt, args...) printk(KERN_DEBUG"comedi%d: me4000: " fmt, dev->minor, ##args) -#else -#define PDEBUG(fmt, args...) /* no debugging, do nothing */ -#endif - -/*============================================================================= - PCI vendor and device IDs - ===========================================================================*/ - -#define PCI_VENDOR_ID_MEILHAUS 0x1402 - -#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 /* Low Cost version */ - -#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 /* Standard version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 /* Isolated version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 /* Standard version with Sample and Hold */ -#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 /* Isolated version with Sample and Hold */ - -#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 /* Standard version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 /* Isolated version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 /* Standard version with Sample and Hold */ -#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 /* Isolated version with Sample and Hold */ - -#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 /* Standard version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 /* Isolated version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 /* Standard version with Sample and Hold */ -#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 /* Isolated version with Sample and Hold */ - -/*============================================================================= - ME-4000 base register offsets - ===========================================================================*/ - -#define ME4000_AO_00_CTRL_REG 0x00 /* R/W */ -#define ME4000_AO_00_STATUS_REG 0x04 /* R/_ */ -#define ME4000_AO_00_FIFO_REG 0x08 /* _/W */ -#define ME4000_AO_00_SINGLE_REG 0x0C /* R/W */ -#define ME4000_AO_00_TIMER_REG 0x10 /* _/W */ - -#define ME4000_AO_01_CTRL_REG 0x18 /* R/W */ -#define ME4000_AO_01_STATUS_REG 0x1C /* R/_ */ -#define ME4000_AO_01_FIFO_REG 0x20 /* _/W */ -#define ME4000_AO_01_SINGLE_REG 0x24 /* R/W */ -#define ME4000_AO_01_TIMER_REG 0x28 /* _/W */ - -#define ME4000_AO_02_CTRL_REG 0x30 /* R/W */ -#define ME4000_AO_02_STATUS_REG 0x34 /* R/_ */ -#define ME4000_AO_02_FIFO_REG 0x38 /* _/W */ -#define ME4000_AO_02_SINGLE_REG 0x3C /* R/W */ -#define ME4000_AO_02_TIMER_REG 0x40 /* _/W */ - -#define ME4000_AO_03_CTRL_REG 0x48 /* R/W */ -#define ME4000_AO_03_STATUS_REG 0x4C /* R/_ */ -#define ME4000_AO_03_FIFO_REG 0x50 /* _/W */ -#define ME4000_AO_03_SINGLE_REG 0x54 /* R/W */ -#define ME4000_AO_03_TIMER_REG 0x58 /* _/W */ - -#define ME4000_AI_CTRL_REG 0x74 /* _/W */ -#define ME4000_AI_STATUS_REG 0x74 /* R/_ */ -#define ME4000_AI_CHANNEL_LIST_REG 0x78 /* _/W */ -#define ME4000_AI_DATA_REG 0x7C /* R/_ */ -#define ME4000_AI_CHAN_TIMER_REG 0x80 /* _/W */ -#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 /* _/W */ -#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 /* _/W */ -#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8C /* _/W */ -#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 /* _/W */ -#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 /* _/W */ -#define ME4000_AI_START_REG 0x98 /* R/_ */ - -#define ME4000_IRQ_STATUS_REG 0x9C /* R/_ */ - -#define ME4000_DIO_PORT_0_REG 0xA0 /* R/W */ -#define ME4000_DIO_PORT_1_REG 0xA4 /* R/W */ -#define ME4000_DIO_PORT_2_REG 0xA8 /* R/W */ -#define ME4000_DIO_PORT_3_REG 0xAC /* R/W */ -#define ME4000_DIO_DIR_REG 0xB0 /* R/W */ - -#define ME4000_AO_LOADSETREG_XX 0xB4 /* R/W */ - -#define ME4000_DIO_CTRL_REG 0xB8 /* R/W */ - -#define ME4000_AO_DEMUX_ADJUST_REG 0xBC /* -/W */ - -#define ME4000_AI_SAMPLE_COUNTER_REG 0xC0 /* _/W */ - -/*============================================================================= - Value to adjust Demux - ===========================================================================*/ - -#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4C - -/*============================================================================= - Counter base register offsets - ===========================================================================*/ - -#define ME4000_CNT_COUNTER_0_REG 0x00 -#define ME4000_CNT_COUNTER_1_REG 0x01 -#define ME4000_CNT_COUNTER_2_REG 0x02 -#define ME4000_CNT_CTRL_REG 0x03 - -/*============================================================================= - PLX base register offsets - ===========================================================================*/ - -#define PLX_INTCSR 0x4C /* Interrupt control and status register */ -#define PLX_ICR 0x50 /* Initialization control register */ - -/*============================================================================= - Bits for the PLX_ICSR register - ===========================================================================*/ - -#define PLX_INTCSR_LOCAL_INT1_EN 0x01 /* If set, local interrupt 1 is enabled (r/w) */ -#define PLX_INTCSR_LOCAL_INT1_POL 0x02 /* If set, local interrupt 1 polarity is active high (r/w) */ -#define PLX_INTCSR_LOCAL_INT1_STATE 0x04 /* If set, local interrupt 1 is active (r/_) */ -#define PLX_INTCSR_LOCAL_INT2_EN 0x08 /* If set, local interrupt 2 is enabled (r/w) */ -#define PLX_INTCSR_LOCAL_INT2_POL 0x10 /* If set, local interrupt 2 polarity is active high (r/w) */ -#define PLX_INTCSR_LOCAL_INT2_STATE 0x20 /* If set, local interrupt 2 is active (r/_) */ -#define PLX_INTCSR_PCI_INT_EN 0x40 /* If set, PCI interrupt is enabled (r/w) */ -#define PLX_INTCSR_SOFT_INT 0x80 /* If set, a software interrupt is generated (r/w) */ - -/*============================================================================= - Bits for the PLX_ICR register - ===========================================================================*/ - -#define PLX_ICR_BIT_EEPROM_CLOCK_SET 0x01000000 -#define PLX_ICR_BIT_EEPROM_CHIP_SELECT 0x02000000 -#define PLX_ICR_BIT_EEPROM_WRITE 0x04000000 -#define PLX_ICR_BIT_EEPROM_READ 0x08000000 -#define PLX_ICR_BIT_EEPROM_VALID 0x10000000 - -#define PLX_ICR_MASK_EEPROM 0x1F000000 - -#define EEPROM_DELAY 1 - -/*============================================================================= - Bits for the ME4000_AO_CTRL_REG register - ===========================================================================*/ - -#define ME4000_AO_CTRL_BIT_MODE_0 0x001 -#define ME4000_AO_CTRL_BIT_MODE_1 0x002 -#define ME4000_AO_CTRL_MASK_MODE 0x003 -#define ME4000_AO_CTRL_BIT_STOP 0x004 -#define ME4000_AO_CTRL_BIT_ENABLE_FIFO 0x008 -#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010 -#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020 -#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080 -#define ME4000_AO_CTRL_BIT_ENABLE_DO 0x100 -#define ME4000_AO_CTRL_BIT_ENABLE_IRQ 0x200 -#define ME4000_AO_CTRL_BIT_RESET_IRQ 0x400 - -/*============================================================================= - Bits for the ME4000_AO_STATUS_REG register - ===========================================================================*/ - -#define ME4000_AO_STATUS_BIT_FSM 0x01 -#define ME4000_AO_STATUS_BIT_FF 0x02 -#define ME4000_AO_STATUS_BIT_HF 0x04 -#define ME4000_AO_STATUS_BIT_EF 0x08 - -/*============================================================================= - Bits for the ME4000_AI_CTRL_REG register - ===========================================================================*/ - -#define ME4000_AI_CTRL_BIT_MODE_0 0x00000001 -#define ME4000_AI_CTRL_BIT_MODE_1 0x00000002 -#define ME4000_AI_CTRL_BIT_MODE_2 0x00000004 -#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008 -#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010 -#define ME4000_AI_CTRL_BIT_STOP 0x00000020 -#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040 -#define ME4000_AI_CTRL_BIT_DATA_FIFO 0x00000080 -#define ME4000_AI_CTRL_BIT_FULLSCALE 0x00000100 -#define ME4000_AI_CTRL_BIT_OFFSET 0x00000200 -#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400 -#define ME4000_AI_CTRL_BIT_EX_TRIG 0x00000800 -#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000 -#define ME4000_AI_CTRL_BIT_EX_IRQ 0x00002000 -#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000 -#define ME4000_AI_CTRL_BIT_LE_IRQ 0x00008000 -#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000 -#define ME4000_AI_CTRL_BIT_HF_IRQ 0x00020000 -#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000 -#define ME4000_AI_CTRL_BIT_SC_IRQ 0x00080000 -#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000 -#define ME4000_AI_CTRL_BIT_SC_RELOAD 0x00200000 -#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000 - -/*============================================================================= - Bits for the ME4000_AI_STATUS_REG register - ===========================================================================*/ - -#define ME4000_AI_STATUS_BIT_EF_CHANNEL 0x00400000 -#define ME4000_AI_STATUS_BIT_HF_CHANNEL 0x00800000 -#define ME4000_AI_STATUS_BIT_FF_CHANNEL 0x01000000 -#define ME4000_AI_STATUS_BIT_EF_DATA 0x02000000 -#define ME4000_AI_STATUS_BIT_HF_DATA 0x04000000 -#define ME4000_AI_STATUS_BIT_FF_DATA 0x08000000 -#define ME4000_AI_STATUS_BIT_LE 0x10000000 -#define ME4000_AI_STATUS_BIT_FSM 0x20000000 - -/*============================================================================= - Bits for the ME4000_IRQ_STATUS_REG register - ===========================================================================*/ - -#define ME4000_IRQ_STATUS_BIT_EX 0x01 -#define ME4000_IRQ_STATUS_BIT_LE 0x02 -#define ME4000_IRQ_STATUS_BIT_AI_HF 0x04 -#define ME4000_IRQ_STATUS_BIT_AO_0_HF 0x08 -#define ME4000_IRQ_STATUS_BIT_AO_1_HF 0x10 -#define ME4000_IRQ_STATUS_BIT_AO_2_HF 0x20 -#define ME4000_IRQ_STATUS_BIT_AO_3_HF 0x40 -#define ME4000_IRQ_STATUS_BIT_SC 0x80 - -/*============================================================================= - Bits for the ME4000_DIO_CTRL_REG register - ===========================================================================*/ - -#define ME4000_DIO_CTRL_BIT_MODE_0 0x0001 -#define ME4000_DIO_CTRL_BIT_MODE_1 0x0002 -#define ME4000_DIO_CTRL_BIT_MODE_2 0x0004 -#define ME4000_DIO_CTRL_BIT_MODE_3 0x0008 -#define ME4000_DIO_CTRL_BIT_MODE_4 0x0010 -#define ME4000_DIO_CTRL_BIT_MODE_5 0x0020 -#define ME4000_DIO_CTRL_BIT_MODE_6 0x0040 -#define ME4000_DIO_CTRL_BIT_MODE_7 0x0080 - -#define ME4000_DIO_CTRL_BIT_FUNCTION_0 0x0100 -#define ME4000_DIO_CTRL_BIT_FUNCTION_1 0x0200 - -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 0x0400 -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 0x0800 -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 0x1000 -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 0x2000 - -/*============================================================================= - Information about the hardware capabilities - ===========================================================================*/ - -struct me4000_ao_info { - int count; - int fifo_count; -}; - -struct me4000_ai_info { - int count; - int sh_count; - int diff_count; - int ex_trig_analog; -}; - -struct me4000_dio_info { - int count; -}; - -struct me4000_cnt_info { - int count; -}; - -struct me4000_board { - const char *name; - unsigned short device_id; - struct me4000_ao_info ao; - struct me4000_ai_info ai; - struct me4000_dio_info dio; - struct me4000_cnt_info cnt; -}; - -#define thisboard ((const struct me4000_board *)dev->board_ptr) - -/*============================================================================= - Global board and subdevice information structures - ===========================================================================*/ - -struct me4000_ao_context { - int irq; - - unsigned long mirror; /* Store the last written value */ - - unsigned long ctrl_reg; - unsigned long status_reg; - unsigned long fifo_reg; - unsigned long single_reg; - unsigned long timer_reg; - unsigned long irq_status_reg; - unsigned long preload_reg; -}; - -struct me4000_ai_context { - int irq; - - unsigned long ctrl_reg; - unsigned long status_reg; - unsigned long channel_list_reg; - unsigned long data_reg; - unsigned long chan_timer_reg; - unsigned long chan_pre_timer_reg; - unsigned long scan_timer_low_reg; - unsigned long scan_timer_high_reg; - unsigned long scan_pre_timer_low_reg; - unsigned long scan_pre_timer_high_reg; - unsigned long start_reg; - unsigned long irq_status_reg; - unsigned long sample_counter_reg; -}; - -struct me4000_dio_context { - unsigned long dir_reg; - unsigned long ctrl_reg; - unsigned long port_0_reg; - unsigned long port_1_reg; - unsigned long port_2_reg; - unsigned long port_3_reg; -}; - -struct me4000_cnt_context { - unsigned long ctrl_reg; - unsigned long counter_0_reg; - unsigned long counter_1_reg; - unsigned long counter_2_reg; -}; - -struct me4000_info { - unsigned long plx_regbase; /* PLX configuration space base address */ - unsigned long me4000_regbase; /* Base address of the ME4000 */ - unsigned long timer_regbase; /* Base address of the timer circuit */ - unsigned long program_regbase; /* Base address to set the program pin for the xilinx */ - - unsigned long plx_regbase_size; /* PLX register set space */ - unsigned long me4000_regbase_size; /* ME4000 register set space */ - unsigned long timer_regbase_size; /* Timer circuit register set space */ - unsigned long program_regbase_size; /* Size of program base address of the ME4000 */ - - unsigned int serial_no; /* Serial number of the board */ - unsigned char hw_revision; /* Hardware revision of the board */ - unsigned short vendor_id; /* Meilhaus vendor id */ - unsigned short device_id; /* Device id */ - - struct pci_dev *pci_dev_p; /* General PCI information */ - - unsigned int irq; /* IRQ assigned from the PCI BIOS */ - - struct me4000_ai_context ai_context; /* Analog input specific context */ - struct me4000_ao_context ao_context[4]; /* Vector with analog output specific context */ - struct me4000_dio_context dio_context; /* Digital I/O specific context */ - struct me4000_cnt_context cnt_context; /* Counter specific context */ -}; - -#define info ((struct me4000_info *)dev->private) - -/*----------------------------------------------------------------------------- - Defines for analog input - ----------------------------------------------------------------------------*/ - -/* General stuff */ -#define ME4000_AI_FIFO_COUNT 2048 - -#define ME4000_AI_MIN_TICKS 66 -#define ME4000_AI_MIN_SAMPLE_TIME 2000 /* Minimum sample time [ns] */ -#define ME4000_AI_BASE_FREQUENCY (unsigned int) 33E6 - -/* Channel list defines and masks */ -#define ME4000_AI_CHANNEL_LIST_COUNT 1024 - -#define ME4000_AI_LIST_INPUT_SINGLE_ENDED 0x000 -#define ME4000_AI_LIST_INPUT_DIFFERENTIAL 0x020 - -#define ME4000_AI_LIST_RANGE_BIPOLAR_10 0x000 -#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 0x040 -#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 0x080 -#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0 - -#define ME4000_AI_LIST_LAST_ENTRY 0x100 - -/*----------------------------------------------------------------------------- - Defines for counters - ----------------------------------------------------------------------------*/ - -#define ME4000_CNT_COUNTER_0 0x00 -#define ME4000_CNT_COUNTER_1 0x40 -#define ME4000_CNT_COUNTER_2 0x80 - -#define ME4000_CNT_MODE_0 0x00 /* Change state if zero crossing */ -#define ME4000_CNT_MODE_1 0x02 /* Retriggerable One-Shot */ -#define ME4000_CNT_MODE_2 0x04 /* Asymmetrical divider */ -#define ME4000_CNT_MODE_3 0x06 /* Symmetrical divider */ -#define ME4000_CNT_MODE_4 0x08 /* Counter start by software trigger */ -#define ME4000_CNT_MODE_5 0x0A /* Counter start by hardware trigger */ - -#endif diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index cda4b224b30..0ff126b1fdf 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -1,70 +1,46 @@ /* - - comedi/drivers/me_daq.c - - Hardware driver for Meilhaus data acquisition cards: - - ME-2000i, ME-2600i, ME-3000vm1 - - Copyright (C) 2002 Michael Hillmann <hillmann@syscongroup.de> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * comedi/drivers/me_daq.c + * Hardware driver for Meilhaus data acquisition cards: + * ME-2000i, ME-2600i, ME-3000vm1 + * + * Copyright (C) 2002 Michael Hillmann <hillmann@syscongroup.de> + * + * 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: me_daq -Description: Meilhaus PCI data acquisition cards -Author: Michael Hillmann <hillmann@syscongroup.de> -Devices: [Meilhaus] ME-2600i (me_daq), ME-2000i -Status: experimental - -Supports: - - Analog Output - -Configuration options: - - [0] - PCI bus number (optional) - [1] - PCI slot number (optional) - - If bus/slot is not specified, the first available PCI - device will be used. - -The 2600 requires a firmware upload, which can be accomplished -using the -i or --init-data option of comedi_config. -The firmware can be -found in the comedi_nonfree_firmware tarball available -from http://www.comedi.org - -*/ + * Driver: me_daq + * Description: Meilhaus PCI data acquisition cards + * Devices: (Meilhaus) ME-2600i [me-2600i] + * (Meilhaus) ME-2000i [me-2000i] + * Author: Michael Hillmann <hillmann@syscongroup.de> + * Status: experimental + * + * Configuration options: not applicable, uses PCI auto config + * + * Supports: + * Analog Input, Analog Output, Digital I/O + */ +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/sched.h> -#include "../comedidev.h" - -#include "comedi_pci.h" -/*#include "me2600_fw.h" */ +#include "../comedidev.h" -#define ME_DRIVER_NAME "me_daq" +#include "plx9052.h" -#define PCI_VENDOR_ID_MEILHAUS 0x1402 -#define ME2000_DEVICE_ID 0x2000 -#define ME2600_DEVICE_ID 0x2600 +#define ME2600_FIRMWARE "me2600_firmware.bin" -#define PLX_INTCSR 0x4C /* PLX interrupt status register */ #define XILINX_DOWNLOAD_RESET 0x42 /* Xilinx registers */ #define ME_CONTROL_1 0x0000 /* - | W */ @@ -146,162 +122,52 @@ from http://www.comedi.org #define ME_COUNTER_STARTDATA_B 0x0022 /* - | W */ #define ME_COUNTER_VALUE_B 0x0022 /* R | - */ -/* Function prototypes */ -static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int me_detach(struct comedi_device *dev); - -static const struct comedi_lrange me2000_ai_range = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } -}; - -static const struct comedi_lrange me2600_ai_range = { - 8, - { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } +static const struct comedi_lrange me_ai_range = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange me2600_ao_range = { - 3, - { - BIP_RANGE(10), - BIP_RANGE(5), - UNI_RANGE(10) - } +static const struct comedi_lrange me_ao_range = { + 3, { + BIP_RANGE(10), + BIP_RANGE(5), + UNI_RANGE(10) + } }; -static DEFINE_PCI_DEVICE_TABLE(me_pci_table) = { - { - PCI_VENDOR_ID_MEILHAUS, ME2600_DEVICE_ID, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - PCI_VENDOR_ID_MEILHAUS, ME2000_DEVICE_ID, PCI_ANY_ID, - PCI_ANY_ID, 0, 0, 0}, { - 0} +enum me_boardid { + BOARD_ME2600, + BOARD_ME2000, }; -MODULE_DEVICE_TABLE(pci, me_pci_table); - -/* Board specification structure */ struct me_board { - const char *name; /* driver name */ - int device_id; - int ao_channel_nbr; /* DA config */ - int ao_resolution; - int ao_resolution_mask; - const struct comedi_lrange *ao_range_list; - int ai_channel_nbr; /* AD config */ - int ai_resolution; - int ai_resolution_mask; - const struct comedi_lrange *ai_range_list; - int dio_channel_nbr; /* DIO config */ + const char *name; + int needs_firmware; + int has_ao; }; static const struct me_board me_boards[] = { - { - /* -- ME-2600i -- */ - .name = ME_DRIVER_NAME, - .device_id = ME2600_DEVICE_ID, - /* Analog Output */ - .ao_channel_nbr = 4, - .ao_resolution = 12, - .ao_resolution_mask = 0x0fff, - .ao_range_list = &me2600_ao_range, - .ai_channel_nbr = 16, - /* Analog Input */ - .ai_resolution = 12, - .ai_resolution_mask = 0x0fff, - .ai_range_list = &me2600_ai_range, - .dio_channel_nbr = 32, - }, - { - /* -- ME-2000i -- */ - .name = ME_DRIVER_NAME, - .device_id = ME2000_DEVICE_ID, - /* Analog Output */ - .ao_channel_nbr = 0, - .ao_resolution = 0, - .ao_resolution_mask = 0, - .ao_range_list = NULL, - .ai_channel_nbr = 16, - /* Analog Input */ - .ai_resolution = 12, - .ai_resolution_mask = 0x0fff, - .ai_range_list = &me2000_ai_range, - .dio_channel_nbr = 32, - } -}; - -#define me_board_nbr (sizeof(me_boards)/sizeof(struct me_board)) - -static struct comedi_driver me_driver = { - .driver_name = ME_DRIVER_NAME, - .module = THIS_MODULE, - .attach = me_attach, - .detach = me_detach, -}; - -static int __devinit me_driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, me_driver.driver_name); -} - -static void __devexit me_driver_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver me_driver_pci_driver = { - .id_table = me_pci_table, - .probe = &me_driver_pci_probe, - .remove = __devexit_p(&me_driver_pci_remove) + [BOARD_ME2600] = { + .name = "me-2600i", + .needs_firmware = 1, + .has_ao = 1, + }, + [BOARD_ME2000] = { + .name = "me-2000i", + }, }; -static int __init me_driver_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&me_driver); - if (retval < 0) - return retval; - - me_driver_pci_driver.name = (char *)me_driver.driver_name; - return pci_register_driver(&me_driver_pci_driver); -} - -static void __exit me_driver_cleanup_module(void) -{ - pci_unregister_driver(&me_driver_pci_driver); - comedi_driver_unregister(&me_driver); -} - -module_init(me_driver_init_module); -module_exit(me_driver_cleanup_module); - -/* Private data structure */ struct me_private_data { - struct pci_dev *pci_device; void __iomem *plx_regbase; /* PLX configuration base address */ void __iomem *me_regbase; /* Base address of the Meilhaus card */ - unsigned long plx_regbase_size; /* Size of PLX configuration space */ - unsigned long me_regbase_size; /* Size of Meilhaus space */ unsigned short control_1; /* Mirror of CONTROL_1 register */ unsigned short control_2; /* Mirror of CONTROL_2 register */ @@ -309,111 +175,104 @@ struct me_private_data { int ao_readback[4]; /* Mirror of analog output data */ }; -#define dev_private ((struct me_private_data *)dev->private) - -/* - * ------------------------------------------------------------------ - * - * Helpful functions - * - * ------------------------------------------------------------------ - */ static inline void sleep(unsigned sec) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(sec * HZ); } -/* - * ------------------------------------------------------------------ - * - * DIGITAL INPUT/OUTPUT SECTION - * - * ------------------------------------------------------------------ - */ static int me_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int bits; - int mask = 1 << CR_CHAN(insn->chanspec); - - /* calculate port */ - if (mask & 0x0000ffff) { /* Port A in use */ - bits = 0x0000ffff; - - /* Enable Port A */ - dev_private->control_2 |= ENABLE_PORT_A; - writew(dev_private->control_2, - dev_private->me_regbase + ME_CONTROL_2); - } else { /* Port B in use */ - - bits = 0xffff0000; - - /* Enable Port B */ - dev_private->control_2 |= ENABLE_PORT_B; - writew(dev_private->control_2, - dev_private->me_regbase + ME_CONTROL_2); - } - - if (data[0]) { - /* Config port as output */ - s->io_bits |= bits; - } else { - /* Config port as input */ - s->io_bits &= ~bits; - } - - return 1; + struct me_private_data *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 16) + mask = 0x0000ffff; + else + mask = 0xffff0000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + if (s->io_bits & 0x0000ffff) + devpriv->control_2 |= ENABLE_PORT_A; + else + devpriv->control_2 &= ~ENABLE_PORT_A; + if (s->io_bits & 0xffff0000) + devpriv->control_2 |= ENABLE_PORT_B; + else + devpriv->control_2 &= ~ENABLE_PORT_B; + + writew(devpriv->control_2, devpriv->me_regbase + ME_CONTROL_2); + + return insn->n; } -/* Digital instant input/outputs */ static int me_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - unsigned int mask = data[0]; - s->state &= ~mask; - s->state |= (mask & data[1]); - - mask &= s->io_bits; - if (mask & 0x0000ffff) { /* Port A */ - writew((s->state & 0xffff), - dev_private->me_regbase + ME_DIO_PORT_A); - } else { - data[1] &= ~0x0000ffff; - data[1] |= readw(dev_private->me_regbase + ME_DIO_PORT_A); + struct me_private_data *dev_private = dev->private; + void __iomem *mmio_porta = dev_private->me_regbase + ME_DIO_PORT_A; + void __iomem *mmio_portb = dev_private->me_regbase + ME_DIO_PORT_B; + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x0000ffff) + writew((s->state & 0xffff), mmio_porta); + if (mask & 0xffff0000) + writew(((s->state >> 16) & 0xffff), mmio_portb); } - if (mask & 0xffff0000) { /* Port B */ - writew(((s->state >> 16) & 0xffff), - dev_private->me_regbase + ME_DIO_PORT_B); - } else { - data[1] &= ~0xffff0000; - data[1] |= readw(dev_private->me_regbase + ME_DIO_PORT_B) << 16; - } + if (s->io_bits & 0x0000ffff) + val = s->state & 0xffff; + else + val = readw(mmio_porta); - return 2; + if (s->io_bits & 0xffff0000) + val |= (s->state & 0xffff0000); + else + val |= (readw(mmio_portb) << 16); + + data[1] = val; + + return insn->n; } -/* - * ------------------------------------------------------------------ - * - * ANALOG INPUT SECTION - * - * ------------------------------------------------------------------ - */ +static int me_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct me_private_data *dev_private = dev->private; + unsigned int status; + + status = readw(dev_private->me_regbase + ME_STATUS); + if ((status & 0x0004) == 0) + return 0; + return -EBUSY; +} -/* Analog instant input */ static int me_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *subdevice, - struct comedi_insn *insn, unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned short value; - int chan = CR_CHAN((&insn->chanspec)[0]); - int rang = CR_RANGE((&insn->chanspec)[0]); - int aref = CR_AREF((&insn->chanspec)[0]); - int i; + struct me_private_data *dev_private = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int rang = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned short val; + int ret; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -431,15 +290,11 @@ static int me_ai_insn_read(struct comedi_device *dev, writew(dev_private->control_2, dev_private->me_regbase + ME_CONTROL_2); /* write to channel list fifo */ - /* b3:b0 are the channel number */ - value = chan & 0x0f; - /* b5:b4 are the channel gain */ - value |= (rang & 0x03) << 4; - /* b6 channel polarity */ - value |= (rang & 0x04) << 4; - /* b7 single or differential */ - value |= ((aref & AREF_DIFF) ? 0x80 : 0); - writew(value & 0xff, dev_private->me_regbase + ME_CHANNEL_LIST); + val = chan & 0x0f; /* b3:b0 channel */ + val |= (rang & 0x03) << 4; /* b5:b4 gain */ + val |= (rang & 0x04) << 4; /* b6 polarity */ + val |= ((aref & AREF_DIFF) ? 0x80 : 0); /* b7 differential */ + writew(val & 0xff, dev_private->me_regbase + ME_CHANNEL_LIST); /* set ADC mode to software trigger */ dev_private->control_1 |= SOFTWARE_TRIGGERED_ADC; @@ -449,20 +304,14 @@ static int me_ai_insn_read(struct comedi_device *dev, readw(dev_private->me_regbase + ME_ADC_START); /* wait for ADC fifo not empty flag */ - for (i = 100000; i > 0; i--) - if (!(readw(dev_private->me_regbase + ME_STATUS) & 0x0004)) - break; + ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); + if (ret) + return ret; /* get value from ADC fifo */ - if (i) { - data[0] = - (readw(dev_private->me_regbase + - ME_READ_AD_FIFO) ^ 0x800) & 0x0FFF; - } else { - printk(KERN_ERR "comedi%d: Cannot get single value\n", - dev->minor); - return -EIO; - } + val = readw(dev_private->me_regbase + ME_READ_AD_FIFO); + val = (val ^ 0x800) & 0x0fff; + data[0] = val; /* stop any running conversion */ dev_private->control_1 &= 0xFFFC; @@ -471,55 +320,14 @@ static int me_ai_insn_read(struct comedi_device *dev, return 1; } -/* - * ------------------------------------------------------------------ - * - * HARDWARE TRIGGERED ANALOG INPUT SECTION - * - * ------------------------------------------------------------------ - */ - -/* Cancel analog input autoscan */ -static int me_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - /* disable interrupts */ - - /* stop any running conversion */ - dev_private->control_1 &= 0xFFFC; - writew(dev_private->control_1, dev_private->me_regbase + ME_CONTROL_1); - - return 0; -} - -/* Test analog input command */ -static int me_ai_do_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - return 0; -} - -/* Analog input command */ -static int me_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *subdevice) -{ - return 0; -} - -/* - * ------------------------------------------------------------------ - * - * ANALOG OUTPUT SECTION - * - * ------------------------------------------------------------------ - */ - -/* Analog instant output */ static int me_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) { - int chan; - int rang; + struct me_private_data *dev_private = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int rang = CR_RANGE(insn->chanspec); int i; /* Enable all DAC */ @@ -532,9 +340,6 @@ static int me_ao_insn_write(struct comedi_device *dev, /* Set dac-control register */ for (i = 0; i < insn->n; i++) { - chan = CR_CHAN((&insn->chanspec)[i]); - rang = CR_RANGE((&insn->chanspec)[i]); - /* clear bits for this channel */ dev_private->dac_control &= ~(0x0880 >> chan); if (rang == 0) @@ -552,7 +357,6 @@ static int me_ao_insn_write(struct comedi_device *dev, /* Set data register */ for (i = 0; i < insn->n; i++) { - chan = CR_CHAN((&insn->chanspec)[i]); writew((data[0] & s->maxdata), dev_private->me_regbase + ME_DAC_DATA_A + (chan << 1)); dev_private->ao_readback[chan] = (data[0] & s->maxdata); @@ -561,43 +365,35 @@ static int me_ao_insn_write(struct comedi_device *dev, /* Update dac with data registers */ readw(dev_private->me_regbase + ME_DAC_UPDATE); - return i; + return insn->n; } -/* Analog output readback */ static int me_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, + 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[CR_CHAN((&insn->chanspec)[i])]; - } + for (i = 0; i < insn->n; i++) + data[i] = dev_private->ao_readback[chan]; - return 1; + return insn->n; } -/* - * ------------------------------------------------------------------ - * - * INITIALISATION SECTION - * - * ------------------------------------------------------------------ - */ - -/* Xilinx firmware download for card: ME-2600i */ static int me2600_xilinx_download(struct comedi_device *dev, - unsigned char *me2600_firmware, - unsigned int length) + const u8 *data, size_t size, + unsigned long context) { + struct me_private_data *dev_private = dev->private; unsigned int value; unsigned int file_length; unsigned int i; /* disable irq's on PLX */ - writel(0x00, dev_private->plx_regbase + PLX_INTCSR); + writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR); /* First, make a dummy read to reset xilinx */ value = readw(dev_private->me_regbase + XILINX_DOWNLOAD_RESET); @@ -617,19 +413,20 @@ static int me2600_xilinx_download(struct comedi_device *dev, * Byte 8-11: date * Byte 12-15: reserved */ - if (length < 16) + if (size < 16) return -EINVAL; - file_length = (((unsigned int)me2600_firmware[0] & 0xff) << 24) + - (((unsigned int)me2600_firmware[1] & 0xff) << 16) + - (((unsigned int)me2600_firmware[2] & 0xff) << 8) + - ((unsigned int)me2600_firmware[3] & 0xff); + + file_length = (((unsigned int)data[0] & 0xff) << 24) + + (((unsigned int)data[1] & 0xff) << 16) + + (((unsigned int)data[2] & 0xff) << 8) + + ((unsigned int)data[3] & 0xff); /* * Loop for writing firmware byte by byte to xilinx - * Firmware data start at offfset 16 + * Firmware data start at offset 16 */ for (i = 0; i < file_length; i++) - writeb((me2600_firmware[16 + i] & 0xff), + writeb((data[16 + i] & 0xff), dev_private->me_regbase + 0x0); /* Write 5 dummy values to xilinx */ @@ -637,12 +434,11 @@ static int me2600_xilinx_download(struct comedi_device *dev, writeb(0x00, dev_private->me_regbase + 0x0); /* Test if there was an error during download -> INTB was thrown */ - value = readl(dev_private->plx_regbase + PLX_INTCSR); - if (value & 0x20) { + value = readl(dev_private->plx_regbase + PLX9052_INTCSR); + if (value & PLX9052_INTCSR_LI2STAT) { /* Disable interrupt */ - writel(0x00, dev_private->plx_regbase + PLX_INTCSR); - printk(KERN_ERR "comedi%d: Xilinx download failed\n", - dev->minor); + writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR); + dev_err(dev->class_dev, "Xilinx download failed\n"); return -EIO; } @@ -650,14 +446,18 @@ static int me2600_xilinx_download(struct comedi_device *dev, sleep(1); /* Enable PLX-Interrupts */ - writel(0x43, dev_private->plx_regbase + PLX_INTCSR); + writel(PLX9052_INTCSR_LI1ENAB | + PLX9052_INTCSR_LI1POL | + PLX9052_INTCSR_PCIENAB, + dev_private->plx_regbase + PLX9052_INTCSR); return 0; } -/* Reset device */ static int me_reset(struct comedi_device *dev) { + struct me_private_data *dev_private = dev->private; + /* Reset board */ writew(0x00, dev_private->me_regbase + ME_CONTROL_1); writew(0x00, dev_private->me_regbase + ME_CONTROL_2); @@ -672,209 +472,92 @@ static int me_reset(struct comedi_device *dev) return 0; } -/* - * Attach - * - * - Register PCI device - * - Declare device driver capability - */ -static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int me_auto_attach(struct comedi_device *dev, + unsigned long context) { - struct pci_dev *pci_device = NULL; - struct comedi_subdevice *subdevice; - struct me_board *board; - resource_size_t plx_regbase_tmp; - unsigned long plx_regbase_size_tmp; - resource_size_t me_regbase_tmp; - unsigned long me_regbase_size_tmp; - resource_size_t swap_regbase_tmp; - unsigned long swap_regbase_size_tmp; - resource_size_t regbase_tmp; - int result, error, i; - - /* Allocate private memory */ - if (alloc_private(dev, sizeof(struct me_private_data)) < 0) - return -ENOMEM; - - /* Probe the device to determine what device in the series it is. */ - for_each_pci_dev(pci_device) { - if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) { - for (i = 0; i < me_board_nbr; i++) { - if (me_boards[i].device_id == - pci_device->device) { - /* - * was a particular bus/slot requested? - */ - if ((it->options[0] != 0) - || (it->options[1] != 0)) { - /* - * are we on the wrong bus/slot? - */ - if (pci_device->bus->number != - it->options[0] - || - PCI_SLOT(pci_device->devfn) - != it->options[1]) { - continue; - } - } - - dev->board_ptr = me_boards + i; - board = - (struct me_board *)dev->board_ptr; - dev_private->pci_device = pci_device; - goto found; - } - } - } - } - - printk(KERN_ERR - "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, it->options[0], it->options[1]); - return -EIO; - -found: - printk(KERN_INFO "comedi%d: found %s at PCI bus %d, slot %d\n", - dev->minor, me_boards[i].name, - pci_device->bus->number, PCI_SLOT(pci_device->devfn)); - - /* Enable PCI device and request PCI regions */ - if (comedi_pci_enable(pci_device, ME_DRIVER_NAME) < 0) { - printk(KERN_ERR "comedi%d: Failed to enable PCI device and " - "request regions\n", dev->minor); - return -EIO; - } - - /* Set data in device structure */ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct me_board *board = NULL; + struct me_private_data *dev_private; + struct comedi_subdevice *s; + int ret; + + if (context < ARRAY_SIZE(me_boards)) + board = &me_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; dev->board_name = board->name; - /* Read PLX register base address [PCI_BASE_ADDRESS #0]. */ - plx_regbase_tmp = pci_resource_start(pci_device, 0); - plx_regbase_size_tmp = pci_resource_len(pci_device, 0); - dev_private->plx_regbase = - ioremap(plx_regbase_tmp, plx_regbase_size_tmp); - dev_private->plx_regbase_size = plx_regbase_size_tmp; - if (!dev_private->plx_regbase) { - printk("comedi%d: Failed to remap I/O memory\n", dev->minor); + dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private)); + if (!dev_private) return -ENOMEM; - } - /* Read Swap base address [PCI_BASE_ADDRESS #5]. */ - - swap_regbase_tmp = pci_resource_start(pci_device, 5); - swap_regbase_size_tmp = pci_resource_len(pci_device, 5); - - if (!swap_regbase_tmp) - printk(KERN_ERR "comedi%d: Swap not present\n", dev->minor); - - /*---------------------------------------------- Workaround start ---*/ - if (plx_regbase_tmp & 0x0080) { - printk(KERN_ERR "comedi%d: PLX-Bug detected\n", dev->minor); - - if (swap_regbase_tmp) { - regbase_tmp = plx_regbase_tmp; - plx_regbase_tmp = swap_regbase_tmp; - swap_regbase_tmp = regbase_tmp; - - result = pci_write_config_dword(pci_device, - PCI_BASE_ADDRESS_0, - plx_regbase_tmp); - if (result != PCIBIOS_SUCCESSFUL) - return -EIO; - - result = pci_write_config_dword(pci_device, - PCI_BASE_ADDRESS_5, - swap_regbase_tmp); - if (result != PCIBIOS_SUCCESSFUL) - return -EIO; - } else { - plx_regbase_tmp -= 0x80; - result = pci_write_config_dword(pci_device, - PCI_BASE_ADDRESS_0, - plx_regbase_tmp); - if (result != PCIBIOS_SUCCESSFUL) - return -EIO; - } - } - /*--------------------------------------------- Workaround end -----*/ + ret = comedi_pci_enable(dev); + if (ret) + return ret; - /* Read Meilhaus register base address [PCI_BASE_ADDRESS #2]. */ + dev_private->plx_regbase = pci_ioremap_bar(pcidev, 0); + if (!dev_private->plx_regbase) + return -ENOMEM; - me_regbase_tmp = pci_resource_start(pci_device, 2); - me_regbase_size_tmp = pci_resource_len(pci_device, 2); - dev_private->me_regbase_size = me_regbase_size_tmp; - dev_private->me_regbase = ioremap(me_regbase_tmp, me_regbase_size_tmp); - if (!dev_private->me_regbase) { - printk(KERN_ERR "comedi%d: Failed to remap I/O memory\n", - dev->minor); + dev_private->me_regbase = pci_ioremap_bar(pcidev, 2); + if (!dev_private->me_regbase) return -ENOMEM; - } + /* Download firmware and reset card */ - if (board->device_id == ME2600_DEVICE_ID) { - unsigned char *aux_data; - int aux_len; - - aux_data = comedi_aux_data(it->options, 0); - aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; - - if (!aux_data || aux_len < 1) { - comedi_error(dev, "You must provide me2600 firmware " - "using the --init-data option of " - "comedi_config"); - return -EINVAL; - } - me2600_xilinx_download(dev, aux_data, aux_len); + if (board->needs_firmware) { + ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, + ME2600_FIRMWARE, + me2600_xilinx_download, 0); + if (ret < 0) + return ret; } - me_reset(dev); - /* device driver capabilities */ - error = alloc_subdevices(dev, 3); - if (error < 0) - return error; - - subdevice = dev->subdevices + 0; - subdevice->type = COMEDI_SUBD_AI; - subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; - subdevice->n_chan = board->ai_channel_nbr; - subdevice->maxdata = board->ai_resolution_mask; - subdevice->len_chanlist = board->ai_channel_nbr; - subdevice->range_table = board->ai_range_list; - subdevice->cancel = me_ai_cancel; - subdevice->insn_read = me_ai_insn_read; - subdevice->do_cmdtest = me_ai_do_cmd_test; - subdevice->do_cmd = me_ai_do_cmd; - - subdevice = dev->subdevices + 1; - subdevice->type = COMEDI_SUBD_AO; - subdevice->subdev_flags = SDF_WRITEABLE | SDF_COMMON; - subdevice->n_chan = board->ao_channel_nbr; - subdevice->maxdata = board->ao_resolution_mask; - subdevice->len_chanlist = board->ao_channel_nbr; - subdevice->range_table = board->ao_range_list; - subdevice->insn_read = me_ao_insn_read; - subdevice->insn_write = me_ao_insn_write; - - subdevice = dev->subdevices + 2; - subdevice->type = COMEDI_SUBD_DIO; - subdevice->subdev_flags = SDF_READABLE | SDF_WRITEABLE; - subdevice->n_chan = board->dio_channel_nbr; - subdevice->maxdata = 1; - subdevice->len_chanlist = board->dio_channel_nbr; - subdevice->range_table = &range_digital; - subdevice->insn_bits = me_dio_insn_bits; - subdevice->insn_config = me_dio_insn_config; - subdevice->io_bits = 0; - - printk(KERN_INFO "comedi%d: " ME_DRIVER_NAME " attached.\n", - dev->minor); + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->len_chanlist = 16; + s->range_table = &me_ai_range; + s->insn_read = me_ai_insn_read; + + s = &dev->subdevices[1]; + if (board->has_ao) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_COMMON; + s->n_chan = 4; + 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; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->n_chan = 32; + s->maxdata = 1; + s->len_chanlist = 32; + s->range_table = &range_digital; + s->insn_bits = me_dio_insn_bits; + s->insn_config = me_dio_insn_config; + return 0; } -/* Detach */ -static int me_detach(struct comedi_device *dev) +static void me_detach(struct comedi_device *dev) { + struct me_private_data *dev_private = dev->private; + if (dev_private) { if (dev_private->me_regbase) { me_reset(dev); @@ -882,16 +565,39 @@ static int me_detach(struct comedi_device *dev) } if (dev_private->plx_regbase) iounmap(dev_private->plx_regbase); - if (dev_private->pci_device) { - if (dev_private->plx_regbase_size) - comedi_pci_disable(dev_private->pci_device); - - pci_dev_put(dev_private->pci_device); - } } - return 0; + comedi_pci_disable(dev); +} + +static struct comedi_driver me_daq_driver = { + .driver_name = "me_daq", + .module = THIS_MODULE, + .auto_attach = me_auto_attach, + .detach = me_detach, +}; + +static int me_daq_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &me_daq_driver, id->driver_data); } +static const struct pci_device_id me_daq_pci_table[] = { + { PCI_VDEVICE(MEILHAUS, 0x2600), BOARD_ME2600 }, + { PCI_VDEVICE(MEILHAUS, 0x2000), BOARD_ME2000 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, me_daq_pci_table); + +static struct pci_driver me_daq_pci_driver = { + .name = "me_daq", + .id_table = me_daq_pci_table, + .probe = me_daq_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(me_daq_driver, me_daq_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(ME2600_FIRMWARE); diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c new file mode 100644 index 00000000000..a4f7d6f138d --- /dev/null +++ b/drivers/staging/comedi/drivers/mf6x4.c @@ -0,0 +1,351 @@ +/* + * comedi/drivers/mf6x4.c + * Driver for Humusoft MF634 and MF624 Data acquisition cards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +/* + * Driver: mf6x4 + * Description: Humusoft MF634 and MF624 Data acquisition card driver + * Devices: Humusoft MF634, Humusoft MF624 + * Author: Rostislav Lisovy <lisovy@gmail.com> + * Status: works + * Updated: + * Configuration Options: none + */ + +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include "../comedidev.h" + +/* Registers present in BAR0 memory region */ +#define MF624_GPIOC_R 0x54 + +#define MF6X4_GPIOC_EOLC /* End Of Last Conversion */ (1 << 17) +#define MF6X4_GPIOC_LDAC /* Load DACs */ (1 << 23) +#define MF6X4_GPIOC_DACEN (1 << 26) + +/* BAR1 registers */ +#define MF6X4_DIN_R 0x10 +#define MF6X4_DIN_M 0xff +#define MF6X4_DOUT_R 0x10 +#define MF6X4_DOUT_M 0xff + +#define MF6X4_ADSTART_R 0x20 +#define MF6X4_ADDATA_R 0x00 +#define MF6X4_ADCTRL_R 0x00 +#define MF6X4_ADCTRL_M 0xff + +#define MF6X4_DA0_R 0x20 +#define MF6X4_DA1_R 0x22 +#define MF6X4_DA2_R 0x24 +#define MF6X4_DA3_R 0x26 +#define MF6X4_DA4_R 0x28 +#define MF6X4_DA5_R 0x2a +#define MF6X4_DA6_R 0x2c +#define MF6X4_DA7_R 0x2e +/* Map DAC cahnnel id to real HW-dependent offset value */ +#define MF6X4_DAC_R(x) (0x20 + ((x) * 2)) +#define MF6X4_DA_M 0x3fff + +/* BAR2 registers */ +#define MF634_GPIOC_R 0x68 + +enum mf6x4_boardid { + BOARD_MF634, + BOARD_MF624, +}; + +struct mf6x4_board { + const char *name; + unsigned int bar_nums[3]; /* We need to keep track of the + order of BARs used by the cards */ +}; + +static const struct mf6x4_board mf6x4_boards[] = { + [BOARD_MF634] = { + .name = "mf634", + .bar_nums = {0, 2, 3}, + }, + [BOARD_MF624] = { + .name = "mf624", + .bar_nums = {0, 2, 4}, + }, +}; + +struct mf6x4_private { + /* + * Documentation for both MF634 and MF624 describes registers + * present in BAR0, 1 and 2 regions. + * The real (i.e. in HW) BAR numbers are different for MF624 + * and MF634 yet we will call them 0, 1, 2 + */ + void __iomem *bar0_mem; + void __iomem *bar1_mem; + void __iomem *bar2_mem; + + /* + * This configuration register has the same function and fields + * for both cards however it lies in different BARs on different + * offsets -- this variable makes the access easier + */ + void __iomem *gpioc_R; + + /* DAC value cache -- used for insn_read function */ + int ao_readback[8]; +}; + +static int mf6x4_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + + data[1] = ioread16(devpriv->bar1_mem + MF6X4_DIN_R) & MF6X4_DIN_M; + + return insn->n; +} + +static int mf6x4_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + + if (comedi_dio_update_state(s, data)) + iowrite16(s->state & MF6X4_DOUT_M, + devpriv->bar1_mem + MF6X4_DOUT_R); + + data[1] = s->state; + + return insn->n; +} + +static int mf6x4_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct mf6x4_private *devpriv = dev->private; + unsigned int status; + + status = ioread32(devpriv->gpioc_R); + if (status & MF6X4_GPIOC_EOLC) + return 0; + return -EBUSY; +} + +static int mf6x4_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + int chan = CR_CHAN(insn->chanspec); + int ret; + int i; + int d; + + /* Set the ADC channel number in the scan list */ + iowrite16((1 << chan) & MF6X4_ADCTRL_M, + devpriv->bar1_mem + MF6X4_ADCTRL_R); + + for (i = 0; i < insn->n; i++) { + /* Trigger ADC conversion by reading ADSTART */ + ioread16(devpriv->bar1_mem + MF6X4_ADSTART_R); + + ret = comedi_timeout(dev, s, insn, mf6x4_ai_eoc, 0); + if (ret) + return ret; + + /* Read the actual value */ + d = ioread16(devpriv->bar1_mem + MF6X4_ADDATA_R); + d &= s->maxdata; + data[i] = d; + } + + iowrite16(0x0, devpriv->bar1_mem + MF6X4_ADCTRL_R); + + return insn->n; +} + +static int mf6x4_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + uint32_t gpioc; + int i; + + /* Enable instantaneous update of converters outputs + Enable DACs */ + gpioc = ioread32(devpriv->gpioc_R); + iowrite32((gpioc & ~MF6X4_GPIOC_LDAC) | MF6X4_GPIOC_DACEN, + devpriv->gpioc_R); + + for (i = 0; i < insn->n; i++) { + iowrite16(data[i] & MF6X4_DA_M, + devpriv->bar1_mem + MF6X4_DAC_R(chan)); + + devpriv->ao_readback[chan] = data[i]; + } + + return insn->n; +} + +static int mf6x4_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct mf6x4_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; +} + +static int mf6x4_auto_attach(struct comedi_device *dev, unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct mf6x4_board *board = NULL; + struct mf6x4_private *devpriv; + struct comedi_subdevice *s; + int ret; + + if (context < ARRAY_SIZE(mf6x4_boards)) + board = &mf6x4_boards[context]; + else + return -ENODEV; + + dev->board_ptr = board; + dev->board_name = board->name; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + devpriv->bar0_mem = pci_ioremap_bar(pcidev, board->bar_nums[0]); + if (!devpriv->bar0_mem) + return -ENODEV; + + devpriv->bar1_mem = pci_ioremap_bar(pcidev, board->bar_nums[1]); + if (!devpriv->bar1_mem) + return -ENODEV; + + devpriv->bar2_mem = pci_ioremap_bar(pcidev, board->bar_nums[2]); + if (!devpriv->bar2_mem) + return -ENODEV; + + if (board == &mf6x4_boards[BOARD_MF634]) + devpriv->gpioc_R = devpriv->bar2_mem + MF634_GPIOC_R; + else + devpriv->gpioc_R = devpriv->bar0_mem + MF624_GPIOC_R; + + + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* ADC */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 8; + s->maxdata = 0x3fff; /* 14 bits ADC */ + s->range_table = &range_bipolar10; + s->insn_read = mf6x4_ai_insn_read; + + /* DAC */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 0x3fff; /* 14 bits DAC */ + s->range_table = &range_bipolar10; + s->insn_write = mf6x4_ao_insn_write; + s->insn_read = mf6x4_ao_insn_read; + + /* DIN */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = mf6x4_di_insn_bits; + + /* DOUT */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = mf6x4_do_insn_bits; + + return 0; +} + +static void mf6x4_detach(struct comedi_device *dev) +{ + struct mf6x4_private *devpriv = dev->private; + + if (devpriv->bar0_mem) + iounmap(devpriv->bar0_mem); + if (devpriv->bar1_mem) + iounmap(devpriv->bar1_mem); + if (devpriv->bar2_mem) + iounmap(devpriv->bar2_mem); + + comedi_pci_disable(dev); +} + +static struct comedi_driver mf6x4_driver = { + .driver_name = "mf6x4", + .module = THIS_MODULE, + .auto_attach = mf6x4_auto_attach, + .detach = mf6x4_detach, +}; + +static int mf6x4_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &mf6x4_driver, id->driver_data); +} + +static const struct pci_device_id mf6x4_pci_table[] = { + { PCI_VDEVICE(HUMUSOFT, 0x0634), BOARD_MF634 }, + { PCI_VDEVICE(HUMUSOFT, 0x0624), BOARD_MF624 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, mf6x4_pci_table); + +static struct pci_driver mf6x4_pci_driver = { + .name = "mf6x4", + .id_table = mf6x4_pci_table, + .probe = mf6x4_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; + +module_comedi_pci_driver(mf6x4_driver, mf6x4_pci_driver); + +MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>"); +MODULE_DESCRIPTION("Comedi MF634 and MF624 DAQ cards driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index fd274e9c7b7..19c029acbc9 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* @@ -49,64 +44,48 @@ /* #define USE_KMALLOC */ -#include "mite.h" +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "comedi_fc.h" -#include "comedi_pci.h" -#include "../comedidev.h" +#include <linux/module.h> +#include <linux/pci.h> -#include <asm/system.h> - -#define PCI_MITE_SIZE 4096 -#define PCI_DAQ_SIZE 4096 -#define PCI_DAQ_SIZE_660X 8192 +#include "../comedidev.h" -struct mite_struct *mite_devices; -EXPORT_SYMBOL(mite_devices); +#include "comedi_fc.h" +#include "mite.h" #define TOP_OF_PAGE(x) ((x)|(~(PAGE_MASK))) -void mite_init(void) +struct mite_struct *mite_alloc(struct pci_dev *pcidev) { - struct pci_dev *pcidev = NULL; struct mite_struct *mite; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_NI) { - unsigned i; - - mite = kzalloc(sizeof(*mite), GFP_KERNEL); - if (!mite) { - printk(KERN_ERR "mite: allocation failed\n"); - pci_dev_put(pcidev); - return; - } - spin_lock_init(&mite->lock); - mite->pcidev = pci_dev_get(pcidev); - for (i = 0; i < MAX_MITE_DMA_CHANNELS; ++i) { - mite->channels[i].mite = mite; - mite->channels[i].channel = i; - mite->channels[i].done = 1; - } - mite->next = mite_devices; - mite_devices = mite; + unsigned int i; + + mite = kzalloc(sizeof(*mite), GFP_KERNEL); + if (mite) { + spin_lock_init(&mite->lock); + mite->pcidev = pcidev; + for (i = 0; i < MAX_MITE_DMA_CHANNELS; ++i) { + mite->channels[i].mite = mite; + mite->channels[i].channel = i; + mite->channels[i].done = 1; } } + return mite; } +EXPORT_SYMBOL_GPL(mite_alloc); static void dump_chip_signature(u32 csigr_bits) { - printk(KERN_INFO "mite: version = %i, type = %i, mite mode = %i," - "interface mode = %i\n", - mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits), - mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits)); - printk(KERN_INFO "mite: num channels = %i, write post fifo depth = %i," - "wins = %i, iowins = %i\n", - mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits), - mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits)); + pr_info("version = %i, type = %i, mite mode = %i, interface mode = %i\n", + mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits), + mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits)); + pr_info("num channels = %i, write post fifo depth = %i, wins = %i, iowins = %i\n", + mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits), + mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits)); } -unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel) +static unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel) { unsigned fcr_bits = readl(mite->mite_io_addr + MITE_FCR(channel)); unsigned empty_count = (fcr_bits >> 16) & 0xff; @@ -117,45 +96,33 @@ unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel) int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1) { unsigned long length; - resource_size_t addr; int i; u32 csigr_bits; unsigned unknown_dma_burst_bits; - if (comedi_pci_enable(mite->pcidev, "mite")) { - printk(KERN_ERR "error enabling mite and requesting io regions\n"); - return -EIO; - } pci_set_master(mite->pcidev); - addr = pci_resource_start(mite->pcidev, 0); - mite->mite_phys_addr = addr; - mite->mite_io_addr = ioremap(addr, PCI_MITE_SIZE); + mite->mite_io_addr = pci_ioremap_bar(mite->pcidev, 0); if (!mite->mite_io_addr) { - printk(KERN_ERR "Failed to remap mite io memory address\n"); + dev_err(&mite->pcidev->dev, + "Failed to remap mite io memory address\n"); return -ENOMEM; } - printk(KERN_INFO "MITE:0x%08llx mapped to %p ", - (unsigned long long)mite->mite_phys_addr, mite->mite_io_addr); + mite->mite_phys_addr = pci_resource_start(mite->pcidev, 0); - addr = pci_resource_start(mite->pcidev, 1); - mite->daq_phys_addr = addr; - length = pci_resource_len(mite->pcidev, 1); - /* - * In case of a 660x board, DAQ size is 8k instead of 4k - * (see as shown by lspci output) - */ - mite->daq_io_addr = ioremap(mite->daq_phys_addr, length); + mite->daq_io_addr = pci_ioremap_bar(mite->pcidev, 1); if (!mite->daq_io_addr) { - printk(KERN_ERR "Failed to remap daq io memory address\n"); + dev_err(&mite->pcidev->dev, + "Failed to remap daq io memory address\n"); return -ENOMEM; } - printk(KERN_INFO "DAQ:0x%08llx mapped to %p\n", - (unsigned long long)mite->daq_phys_addr, mite->daq_io_addr); + mite->daq_phys_addr = pci_resource_start(mite->pcidev, 1); + length = pci_resource_len(mite->pcidev, 1); if (use_iodwbsr_1) { writel(0, mite->mite_io_addr + MITE_IODWBSR); - printk(KERN_INFO "mite: using I/O Window Base Size register 1\n"); + dev_info(&mite->pcidev->dev, + "using I/O Window Base Size register 1\n"); writel(mite->daq_phys_addr | WENAB | MITE_IODWBSR_1_WSIZE_bits(length), mite->mite_io_addr + MITE_IODWBSR_1); @@ -180,9 +147,9 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1) csigr_bits = readl(mite->mite_io_addr + MITE_CSIGR); mite->num_channels = mite_csigr_dmac(csigr_bits); if (mite->num_channels > MAX_MITE_DMA_CHANNELS) { - printk(KERN_WARNING "mite: bug? chip claims to have %i dma " - "channels. Setting to %i.\n", - mite->num_channels, MAX_MITE_DMA_CHANNELS); + dev_warn(&mite->pcidev->dev, + "mite: bug? chip claims to have %i dma channels. Setting to %i.\n", + mite->num_channels, MAX_MITE_DMA_CHANNELS); mite->num_channels = MAX_MITE_DMA_CHANNELS; } dump_chip_signature(csigr_bits); @@ -195,29 +162,16 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1) mite->mite_io_addr + MITE_CHCR(i)); } mite->fifo_size = mite_fifo_size(mite, 0); - printk(KERN_INFO "mite: fifo size is %i.\n", mite->fifo_size); - mite->used = 1; - + dev_info(&mite->pcidev->dev, "fifo size is %i.\n", mite->fifo_size); return 0; } -EXPORT_SYMBOL(mite_setup2); +EXPORT_SYMBOL_GPL(mite_setup2); int mite_setup(struct mite_struct *mite) { return mite_setup2(mite, 0); } -EXPORT_SYMBOL(mite_setup); - -void mite_cleanup(void) -{ - struct mite_struct *mite, *next; - - for (mite = mite_devices; mite; mite = next) { - pci_dev_put(mite->pcidev); - next = mite->next; - kfree(mite); - } -} +EXPORT_SYMBOL_GPL(mite_setup); void mite_unsetup(struct mite_struct *mite) { @@ -234,30 +188,45 @@ void mite_unsetup(struct mite_struct *mite) iounmap(mite->daq_io_addr); mite->daq_io_addr = NULL; } - if (mite->mite_phys_addr) { - comedi_pci_disable(mite->pcidev); + if (mite->mite_phys_addr) mite->mite_phys_addr = 0; - } - - mite->used = 0; } -EXPORT_SYMBOL(mite_unsetup); +EXPORT_SYMBOL_GPL(mite_unsetup); + +struct mite_dma_descriptor_ring *mite_alloc_ring(struct mite_struct *mite) +{ + struct mite_dma_descriptor_ring *ring = + kmalloc(sizeof(struct mite_dma_descriptor_ring), GFP_KERNEL); + + if (ring == NULL) + return ring; + ring->hw_dev = get_device(&mite->pcidev->dev); + if (ring->hw_dev == NULL) { + kfree(ring); + return NULL; + } + ring->n_links = 0; + ring->descriptors = NULL; + ring->descriptors_dma_addr = 0; + return ring; +}; +EXPORT_SYMBOL_GPL(mite_alloc_ring); -void mite_list_devices(void) +void mite_free_ring(struct mite_dma_descriptor_ring *ring) { - struct mite_struct *mite, *next; - - printk(KERN_INFO "Available NI device IDs:"); - if (mite_devices) - for (mite = mite_devices; mite; mite = next) { - next = mite->next; - printk(KERN_INFO " 0x%04x", mite_device_id(mite)); - if (mite->used) - printk(KERN_INFO "(used)"); + if (ring) { + if (ring->descriptors) { + dma_free_coherent(ring->hw_dev, + ring->n_links * + sizeof(struct mite_dma_descriptor), + ring->descriptors, + ring->descriptors_dma_addr); } - printk(KERN_INFO "\n"); -} -EXPORT_SYMBOL(mite_list_devices); + put_device(ring->hw_dev); + kfree(ring); + } +}; +EXPORT_SYMBOL_GPL(mite_free_ring); struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite, struct @@ -284,7 +253,7 @@ struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite, spin_unlock_irqrestore(&mite->lock, flags); return channel; } -EXPORT_SYMBOL(mite_request_channel_in_range); +EXPORT_SYMBOL_GPL(mite_request_channel_in_range); void mite_release_channel(struct mite_channel *mite_chan) { @@ -311,7 +280,7 @@ void mite_release_channel(struct mite_channel *mite_chan) } spin_unlock_irqrestore(&mite->lock, flags); } -EXPORT_SYMBOL(mite_release_channel); +EXPORT_SYMBOL_GPL(mite_release_channel); void mite_dma_arm(struct mite_channel *mite_chan) { @@ -319,7 +288,6 @@ void mite_dma_arm(struct mite_channel *mite_chan) int chor; unsigned long flags; - MDPRINTK("mite_dma_arm ch%i\n", channel); /* * memory barrier is intended to insure any twiddling with the buffer * is done before writing to the mite to arm dma transfer @@ -334,13 +302,14 @@ void mite_dma_arm(struct mite_channel *mite_chan) spin_unlock_irqrestore(&mite->lock, flags); /* mite_dma_tcr(mite, channel); */ } -EXPORT_SYMBOL(mite_dma_arm); +EXPORT_SYMBOL_GPL(mite_dma_arm); /**************************************/ int mite_buf_change(struct mite_dma_descriptor_ring *ring, - struct comedi_async *async) + struct comedi_subdevice *s) { + struct comedi_async *async = s->async; unsigned int n_links; int i; @@ -360,14 +329,13 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring, n_links = async->prealloc_bufsz >> PAGE_SHIFT; - MDPRINTK("ring->hw_dev=%p, n_links=0x%04x\n", ring->hw_dev, n_links); - ring->descriptors = dma_alloc_coherent(ring->hw_dev, n_links * sizeof(struct mite_dma_descriptor), &ring->descriptors_dma_addr, GFP_KERNEL); if (!ring->descriptors) { - printk(KERN_ERR "mite: ring buffer allocation failed\n"); + dev_err(s->device->class_dev, + "mite: ring buffer allocation failed\n"); return -ENOMEM; } ring->n_links = n_links; @@ -375,7 +343,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring, for (i = 0; i < n_links; i++) { ring->descriptors[i].count = cpu_to_le32(PAGE_SIZE); ring->descriptors[i].addr = - cpu_to_le32(async->buf_page_list[i].dma_addr); + cpu_to_le32(async->buf_map->page_list[i].dma_addr); ring->descriptors[i].next = cpu_to_le32(ring->descriptors_dma_addr + (i + 1) * @@ -390,7 +358,7 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring, smp_wmb(); return 0; } -EXPORT_SYMBOL(mite_buf_change); +EXPORT_SYMBOL_GPL(mite_buf_change); void mite_prep_dma(struct mite_channel *mite_chan, unsigned int num_device_bits, unsigned int num_memory_bits) @@ -398,8 +366,6 @@ void mite_prep_dma(struct mite_channel *mite_chan, unsigned int chor, chcr, mcr, dcr, lkcr; struct mite_struct *mite = mite_chan->mite; - MDPRINTK("mite_prep_dma ch%i\n", mite_chan->channel); - /* reset DMA and FIFO */ chor = CHOR_DMARESET | CHOR_FRESET; writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); @@ -444,8 +410,7 @@ void mite_prep_dma(struct mite_channel *mite_chan, mcr |= CR_PSIZE32; break; default: - printk(KERN_WARNING "mite: bug! invalid mem bit width for dma " - "transfer\n"); + pr_warn("bug! invalid mem bit width for dma transfer\n"); break; } writel(mcr, mite->mite_io_addr + MITE_MCR(mite_chan->channel)); @@ -464,8 +429,7 @@ void mite_prep_dma(struct mite_channel *mite_chan, dcr |= CR_PSIZE32; break; default: - printk(KERN_WARNING "mite: bug! invalid dev bit width for dma " - "transfer\n"); + pr_warn("bug! invalid dev bit width for dma transfer\n"); break; } writel(dcr, mite->mite_io_addr + MITE_DCR(mite_chan->channel)); @@ -480,12 +444,10 @@ void mite_prep_dma(struct mite_channel *mite_chan, /* starting address for link chaining */ writel(mite_chan->ring->descriptors_dma_addr, mite->mite_io_addr + MITE_LKAR(mite_chan->channel)); - - MDPRINTK("exit mite_prep_dma\n"); } -EXPORT_SYMBOL(mite_prep_dma); +EXPORT_SYMBOL_GPL(mite_prep_dma); -u32 mite_device_bytes_transferred(struct mite_channel *mite_chan) +static u32 mite_device_bytes_transferred(struct mite_channel *mite_chan) { struct mite_struct *mite = mite_chan->mite; return readl(mite->mite_io_addr + MITE_DAR(mite_chan->channel)); @@ -497,7 +459,7 @@ u32 mite_bytes_in_transit(struct mite_channel *mite_chan) return readl(mite->mite_io_addr + MITE_FCR(mite_chan->channel)) & 0x000000FF; } -EXPORT_SYMBOL(mite_bytes_in_transit); +EXPORT_SYMBOL_GPL(mite_bytes_in_transit); /* returns lower bound for number of bytes transferred from device to memory */ u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan) @@ -507,7 +469,7 @@ u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan) device_byte_count = mite_device_bytes_transferred(mite_chan); return device_byte_count - mite_bytes_in_transit(mite_chan); } -EXPORT_SYMBOL(mite_bytes_written_to_memory_lb); +EXPORT_SYMBOL_GPL(mite_bytes_written_to_memory_lb); /* returns upper bound for number of bytes transferred from device to memory */ u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan) @@ -517,7 +479,7 @@ u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan) in_transit_count = mite_bytes_in_transit(mite_chan); return mite_device_bytes_transferred(mite_chan) - in_transit_count; } -EXPORT_SYMBOL(mite_bytes_written_to_memory_ub); +EXPORT_SYMBOL_GPL(mite_bytes_written_to_memory_ub); /* returns lower bound for number of bytes read from memory to device */ u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan) @@ -527,7 +489,7 @@ u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan) device_byte_count = mite_device_bytes_transferred(mite_chan); return device_byte_count + mite_bytes_in_transit(mite_chan); } -EXPORT_SYMBOL(mite_bytes_read_from_memory_lb); +EXPORT_SYMBOL_GPL(mite_bytes_read_from_memory_lb); /* returns upper bound for number of bytes read from memory to device */ u32 mite_bytes_read_from_memory_ub(struct mite_channel *mite_chan) @@ -537,7 +499,7 @@ u32 mite_bytes_read_from_memory_ub(struct mite_channel *mite_chan) in_transit_count = mite_bytes_in_transit(mite_chan); return mite_device_bytes_transferred(mite_chan) + in_transit_count; } -EXPORT_SYMBOL(mite_bytes_read_from_memory_ub); +EXPORT_SYMBOL_GPL(mite_bytes_read_from_memory_ub); unsigned mite_dma_tcr(struct mite_channel *mite_chan) { @@ -547,12 +509,10 @@ unsigned mite_dma_tcr(struct mite_channel *mite_chan) lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel)); tcr = readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel)); - MDPRINTK("mite_dma_tcr ch%i, lkar=0x%08x tcr=%d\n", mite_chan->channel, - lkar, tcr); return tcr; } -EXPORT_SYMBOL(mite_dma_tcr); +EXPORT_SYMBOL_GPL(mite_dma_tcr); void mite_dma_disarm(struct mite_channel *mite_chan) { @@ -563,23 +523,24 @@ void mite_dma_disarm(struct mite_channel *mite_chan) chor = CHOR_ABORT; writel(chor, mite->mite_io_addr + MITE_CHOR(mite_chan->channel)); } -EXPORT_SYMBOL(mite_dma_disarm); +EXPORT_SYMBOL_GPL(mite_dma_disarm); int mite_sync_input_dma(struct mite_channel *mite_chan, - struct comedi_async *async) + struct comedi_subdevice *s) { + struct comedi_async *async = s->async; int count; unsigned int nbytes, old_alloc_count; - const unsigned bytes_per_scan = cfc_bytes_per_scan(async->subdevice); old_alloc_count = async->buf_write_alloc_count; /* write alloc as much as we can */ - comedi_buf_write_alloc(async, async->prealloc_bufsz); + comedi_buf_write_alloc(s, async->prealloc_bufsz); nbytes = mite_bytes_written_to_memory_lb(mite_chan); if ((int)(mite_bytes_written_to_memory_ub(mite_chan) - old_alloc_count) > 0) { - printk("mite: DMA overwrite of free area\n"); + dev_warn(s->device->class_dev, + "mite: DMA overwrite of free area\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; } @@ -590,40 +551,33 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, if (count <= 0) return 0; - comedi_buf_write_free(async, count); - - async->scan_progress += count; - if (async->scan_progress >= bytes_per_scan) { - async->scan_progress %= bytes_per_scan; - async->events |= COMEDI_CB_EOS; - } + comedi_buf_write_free(s, count); + cfc_inc_scan_progress(s, count); async->events |= COMEDI_CB_BLOCK; return 0; } -EXPORT_SYMBOL(mite_sync_input_dma); +EXPORT_SYMBOL_GPL(mite_sync_input_dma); int mite_sync_output_dma(struct mite_channel *mite_chan, - struct comedi_async *async) + struct comedi_subdevice *s) { - int count; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + u32 stop_count = cmd->stop_arg * cfc_bytes_per_scan(s); + unsigned int old_alloc_count = async->buf_read_alloc_count; u32 nbytes_ub, nbytes_lb; - unsigned int old_alloc_count; - u32 stop_count = - async->cmd.stop_arg * cfc_bytes_per_scan(async->subdevice); + int count; - old_alloc_count = async->buf_read_alloc_count; /* read alloc as much as we can */ - comedi_buf_read_alloc(async, async->prealloc_bufsz); + comedi_buf_read_alloc(s, async->prealloc_bufsz); nbytes_lb = mite_bytes_read_from_memory_lb(mite_chan); - if (async->cmd.stop_src == TRIG_COUNT && - (int)(nbytes_lb - stop_count) > 0) + if (cmd->stop_src == TRIG_COUNT && (int)(nbytes_lb - stop_count) > 0) nbytes_lb = stop_count; nbytes_ub = mite_bytes_read_from_memory_ub(mite_chan); - if (async->cmd.stop_src == TRIG_COUNT && - (int)(nbytes_ub - stop_count) > 0) + if (cmd->stop_src == TRIG_COUNT && (int)(nbytes_ub - stop_count) > 0) nbytes_ub = stop_count; if ((int)(nbytes_ub - old_alloc_count) > 0) { - printk(KERN_ERR "mite: DMA underrun\n"); + dev_warn(s->device->class_dev, "mite: DMA underrun\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; } @@ -632,12 +586,12 @@ int mite_sync_output_dma(struct mite_channel *mite_chan, return 0; if (count) { - comedi_buf_read_free(async, count); + comedi_buf_read_free(s, count); async->events |= COMEDI_CB_BLOCK; } return 0; } -EXPORT_SYMBOL(mite_sync_output_dma); +EXPORT_SYMBOL_GPL(mite_sync_output_dma); unsigned mite_get_status(struct mite_channel *mite_chan) { @@ -656,7 +610,7 @@ unsigned mite_get_status(struct mite_channel *mite_chan) spin_unlock_irqrestore(&mite->lock, flags); return status; } -EXPORT_SYMBOL(mite_get_status); +EXPORT_SYMBOL_GPL(mite_get_status); int mite_done(struct mite_channel *mite_chan) { @@ -670,161 +624,19 @@ int mite_done(struct mite_channel *mite_chan) spin_unlock_irqrestore(&mite->lock, flags); return done; } -EXPORT_SYMBOL(mite_done); - -#ifdef DEBUG_MITE - -static void mite_decode(char **bit_str, unsigned int bits); +EXPORT_SYMBOL_GPL(mite_done); -/* names of bits in mite registers */ - -static const char *const mite_CHOR_strings[] = { - "start", "cont", "stop", "abort", - "freset", "clrlc", "clrrb", "clrdone", - "clr_lpause", "set_lpause", "clr_send_tc", - "set_send_tc", "12", "13", "14", - "15", "16", "17", "18", - "19", "20", "21", "22", - "23", "24", "25", "26", - "27", "28", "29", "30", - "dmareset", -}; - -static const char *const mite_CHCR_strings[] = { - "continue", "ringbuff", "2", "3", - "4", "5", "6", "7", - "8", "9", "10", "11", - "12", "13", "bursten", "fifodis", - "clr_cont_rb_ie", "set_cont_rb_ie", "clr_lc_ie", "set_lc_ie", - "clr_drdy_ie", "set_drdy_ie", "clr_mrdy_ie", "set_mrdy_ie", - "clr_done_ie", "set_done_ie", "clr_sar_ie", "set_sar_ie", - "clr_linkp_ie", "set_linkp_ie", "clr_dma_ie", "set_dma_ie", -}; - -static const char *const mite_MCR_strings[] = { - "amdevice", "1", "2", "3", - "4", "5", "portio", "portvxi", - "psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "11", - "12", "13", "blocken", "berhand", - "reqsintlim/reqs0", "reqs1", "reqs2", "rd32", - "rd512", "rl1", "rl2", "rl8", - "24", "25", "26", "27", - "28", "29", "30", "stopen", -}; - -static const char *const mite_DCR_strings[] = { - "amdevice", "1", "2", "3", - "4", "5", "portio", "portvxi", - "psizebyte", "psizehalf (byte & half = word)", "aseqxp1", "aseqxp2", - "aseqxp8", "13", "blocken", "berhand", - "reqsintlim", "reqs1", "reqs2", "rd32", - "rd512", "rl1", "rl2", "rl8", - "23", "24", "25", "27", - "28", "wsdevc", "wsdevs", "rwdevpack", -}; - -static const char *const mite_LKCR_strings[] = { - "amdevice", "1", "2", "3", - "4", "5", "portio", "portvxi", - "psizebyte", "psizehalf (byte & half = word)", "asequp", "aseqdown", - "12", "13", "14", "berhand", - "16", "17", "18", "rd32", - "rd512", "rl1", "rl2", "rl8", - "24", "25", "26", "27", - "28", "29", "30", "chngend", -}; - -static const char *const mite_CHSR_strings[] = { - "d.err0", "d.err1", "m.err0", "m.err1", - "l.err0", "l.err1", "drq0", "drq1", - "end", "xferr", "operr0", "operr1", - "stops", "habort", "sabort", "error", - "16", "conts_rb", "18", "linkc", - "20", "drdy", "22", "mrdy", - "24", "done", "26", "sars", - "28", "lpauses", "30", "int", -}; - -void mite_dump_regs(struct mite_channel *mite_chan) -{ - unsigned long mite_io_addr = - (unsigned long)mite_chan->mite->mite_io_addr; - unsigned long addr = 0; - unsigned long temp = 0; - - printk(KERN_DEBUG "mite_dump_regs ch%i\n", mite_chan->channel); - printk(KERN_DEBUG "mite address is =0x%08lx\n", mite_io_addr); - - addr = mite_io_addr + MITE_CHOR(channel); - printk(KERN_DEBUG "mite status[CHOR]at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_CHOR_strings, temp); - addr = mite_io_addr + MITE_CHCR(channel); - printk(KERN_DEBUG "mite status[CHCR]at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_CHCR_strings, temp); - addr = mite_io_addr + MITE_TCR(channel); - printk(KERN_DEBUG "mite status[TCR] at 0x%08lx =0x%08x\n", addr, - readl(addr)); - addr = mite_io_addr + MITE_MCR(channel); - printk(KERN_DEBUG "mite status[MCR] at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_MCR_strings, temp); - - addr = mite_io_addr + MITE_MAR(channel); - printk(KERN_DEBUG "mite status[MAR] at 0x%08lx =0x%08x\n", addr, - readl(addr)); - addr = mite_io_addr + MITE_DCR(channel); - printk(KERN_DEBUG "mite status[DCR] at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_DCR_strings, temp); - addr = mite_io_addr + MITE_DAR(channel); - printk(KERN_DEBUG "mite status[DAR] at 0x%08lx =0x%08x\n", addr, - readl(addr)); - addr = mite_io_addr + MITE_LKCR(channel); - printk(KERN_DEBUG "mite status[LKCR]at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_LKCR_strings, temp); - addr = mite_io_addr + MITE_LKAR(channel); - printk(KERN_DEBUG "mite status[LKAR]at 0x%08lx =0x%08x\n", addr, - readl(addr)); - addr = mite_io_addr + MITE_CHSR(channel); - printk(KERN_DEBUG "mite status[CHSR]at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_CHSR_strings, temp); - addr = mite_io_addr + MITE_FCR(channel); - printk(KERN_DEBUG "mite status[FCR] at 0x%08lx =0x%08x\n\n", addr, - readl(addr)); -} -EXPORT_SYMBOL(mite_dump_regs); - -static void mite_decode(char **bit_str, unsigned int bits) +static int __init mite_module_init(void) { - int i; - - for (i = 31; i >= 0; i--) { - if (bits & (1 << i)) - printk(KERN_DEBUG " %s", bit_str[i]); - } - printk(KERN_DEBUG "\n"); -} -EXPORT_SYMBOL(mite_decode); -#endif - -#ifdef MODULE -int __init init_module(void) -{ - mite_init(); - mite_list_devices(); - return 0; } -void __exit cleanup_module(void) +static void __exit mite_module_exit(void) { - mite_cleanup(); } -#endif + +module_init(mite_module_init); +module_exit(mite_module_exit); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h index 999551f54c2..e6e58e989b7 100644 --- a/drivers/staging/comedi/drivers/mite.h +++ b/drivers/staging/comedi/drivers/mite.h @@ -14,34 +14,24 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _MITE_H_ #define _MITE_H_ #include <linux/pci.h> +#include <linux/log2.h> +#include <linux/slab.h> #include "../comedidev.h" -/* #define DEBUG_MITE */ #define PCIMIO_COMPAT -#ifdef DEBUG_MITE -#define MDPRINTK(format, args...) printk(format , ## args) -#else -#define MDPRINTK(format, args...) -#endif - #define MAX_MITE_DMA_CHANNELS 8 struct mite_dma_descriptor { - u32 count; - u32 addr; - u32 next; + __le32 count; + __le32 addr; + __le32 next; u32 dar; }; @@ -61,15 +51,11 @@ struct mite_channel { }; struct mite_struct { - struct mite_struct *next; - int used; - struct pci_dev *pcidev; resource_size_t mite_phys_addr; - void *mite_io_addr; + void __iomem *mite_io_addr; resource_size_t daq_phys_addr; - void *daq_io_addr; - + void __iomem *daq_io_addr; struct mite_channel channels[MAX_MITE_DMA_CHANNELS]; short channel_allocated[MAX_MITE_DMA_CHANNELS]; int num_channels; @@ -77,41 +63,12 @@ struct mite_struct { spinlock_t lock; }; -static inline struct mite_dma_descriptor_ring *mite_alloc_ring(struct - mite_struct - *mite) -{ - struct mite_dma_descriptor_ring *ring = - kmalloc(sizeof(struct mite_dma_descriptor_ring), GFP_KERNEL); - if (ring == NULL) - return ring; - ring->hw_dev = get_device(&mite->pcidev->dev); - if (ring->hw_dev == NULL) { - kfree(ring); - return NULL; - } - ring->n_links = 0; - ring->descriptors = NULL; - ring->descriptors_dma_addr = 0; - return ring; -}; - -static inline void mite_free_ring(struct mite_dma_descriptor_ring *ring) -{ - if (ring) { - if (ring->descriptors) { - dma_free_coherent(ring->hw_dev, - ring->n_links * - sizeof(struct mite_dma_descriptor), - ring->descriptors, - ring->descriptors_dma_addr); - } - put_device(ring->hw_dev); - kfree(ring); - } -}; +struct mite_struct *mite_alloc(struct pci_dev *pcidev); -extern struct mite_struct *mite_devices; +static inline void mite_free(struct mite_struct *mite) +{ + kfree(mite); +} static inline unsigned int mite_irq(struct mite_struct *mite) { @@ -123,12 +80,11 @@ static inline unsigned int mite_device_id(struct mite_struct *mite) return mite->pcidev->device; }; -void mite_init(void); -void mite_cleanup(void); int mite_setup(struct mite_struct *mite); int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1); void mite_unsetup(struct mite_struct *mite); -void mite_list_devices(void); +struct mite_dma_descriptor_ring *mite_alloc_ring(struct mite_struct *mite); +void mite_free_ring(struct mite_dma_descriptor_ring *ring); struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite, struct mite_dma_descriptor_ring @@ -150,9 +106,9 @@ unsigned mite_dma_tcr(struct mite_channel *mite_chan); void mite_dma_arm(struct mite_channel *mite_chan); void mite_dma_disarm(struct mite_channel *mite_chan); int mite_sync_input_dma(struct mite_channel *mite_chan, - struct comedi_async *async); + struct comedi_subdevice *s); int mite_sync_output_dma(struct mite_channel *mite_chan, - struct comedi_async *async); + struct comedi_subdevice *s); u32 mite_bytes_written_to_memory_lb(struct mite_channel *mite_chan); u32 mite_bytes_written_to_memory_ub(struct mite_channel *mite_chan); u32 mite_bytes_read_from_memory_lb(struct mite_channel *mite_chan); @@ -164,12 +120,7 @@ int mite_done(struct mite_channel *mite_chan); void mite_prep_dma(struct mite_channel *mite_chan, unsigned int num_device_bits, unsigned int num_memory_bits); int mite_buf_change(struct mite_dma_descriptor_ring *ring, - struct comedi_async *async); - -#ifdef DEBUG_MITE -void mite_print_chsr(unsigned int chsr); -void mite_dump_regs(struct mite_channel *mite_chan); -#endif + struct comedi_subdevice *s); static inline int CHAN_OFFSET(int channel) { @@ -279,8 +230,9 @@ enum MITE_IODWBSR_bits { static inline unsigned MITE_IODWBSR_1_WSIZE_bits(unsigned size) { unsigned order = 0; - while (size >>= 1) - ++order; + + BUG_ON(size == 0); + order = ilog2(size); BUG_ON(order < 1); return (order - 1) & 0x1f; } @@ -427,12 +379,10 @@ static inline int CR_RL(unsigned int retry_limit) { int value = 0; - while (retry_limit) { - retry_limit >>= 1; - value++; - } + if (retry_limit) + value = 1 + ilog2(retry_limit); if (value > 0x7) - printk("comedi: bug! retry_limit too large\n"); + value = 0x7; return (value & 0x7) << 21; } diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index dd09a6d46e5..f770400a0e8 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: mpc624 @@ -56,9 +51,9 @@ Configuration Options: 1 -10.1V .. +10.1V */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <linux/delay.h> /* Consecutive I/O port addresses */ @@ -122,13 +117,12 @@ Configuration Options: #define MPC624_SPEED_6_875_Hz \ (MPC624_OSR4 | MPC624_OSR3 | MPC624_OSR2 | MPC624_OSR1 | MPC624_OSR0) /* -------------------------------------------------------------------------- */ -struct skel_private { +struct mpc624_private { /* set by mpc624_attach() from driver's parameters */ unsigned long int ulConvertionRate; }; -#define devpriv ((struct skel_private *)dev->private) /* -------------------------------------------------------------------------- */ static const struct comedi_lrange range_mpc624_bipolar1 = { 1, @@ -148,152 +142,33 @@ static const struct comedi_lrange range_mpc624_bipolar10 = { } }; -/* -------------------------------------------------------------------------- */ -static int mpc624_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int mpc624_detach(struct comedi_device *dev); -/* -------------------------------------------------------------------------- */ -static struct comedi_driver driver_mpc624 = { - .driver_name = "mpc624", - .module = THIS_MODULE, - .attach = mpc624_attach, - .detach = mpc624_detach -}; - -/* -------------------------------------------------------------------------- */ -static int mpc624_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -/* -------------------------------------------------------------------------- */ -static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int mpc624_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: mpc624 [0x%04lx, ", dev->minor, iobase); - if (request_region(iobase, MPC624_SIZE, "mpc624") == NULL) { - printk(KERN_ERR "I/O port(s) in use\n"); - return -EIO; - } - - dev->iobase = iobase; - dev->board_name = "mpc624"; - - /* Private structure initialization */ - if (alloc_private(dev, sizeof(struct skel_private)) < 0) - return -ENOMEM; - - switch (it->options[1]) { - case 0: - devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; - printk(KERN_INFO "3.52 kHz, "); - break; - case 1: - devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz; - printk(KERN_INFO "1.76 kHz, "); - break; - case 2: - devpriv->ulConvertionRate = MPC624_SPEED_880_Hz; - printk(KERN_INFO "880 Hz, "); - break; - case 3: - devpriv->ulConvertionRate = MPC624_SPEED_440_Hz; - printk(KERN_INFO "440 Hz, "); - break; - case 4: - devpriv->ulConvertionRate = MPC624_SPEED_220_Hz; - printk(KERN_INFO "220 Hz, "); - break; - case 5: - devpriv->ulConvertionRate = MPC624_SPEED_110_Hz; - printk(KERN_INFO "110 Hz, "); - break; - case 6: - devpriv->ulConvertionRate = MPC624_SPEED_55_Hz; - printk(KERN_INFO "55 Hz, "); - break; - case 7: - devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz; - printk(KERN_INFO "27.5 Hz, "); - break; - case 8: - devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz; - printk(KERN_INFO "13.75 Hz, "); - break; - case 9: - devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz; - printk(KERN_INFO "6.875 Hz, "); - break; - default: - printk - (KERN_ERR "illegal conversion rate setting!" - " Valid numbers are 0..9. Using 9 => 6.875 Hz, "); - devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; - } - - /* Subdevices structures */ - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF; - s->n_chan = 8; - switch (it->options[1]) { - default: - s->maxdata = 0x3FFFFFFF; - printk(KERN_INFO "30 bit, "); - } - - switch (it->options[1]) { - case 0: - s->range_table = &range_mpc624_bipolar1; - printk(KERN_INFO "1.01V]: "); - break; - default: - s->range_table = &range_mpc624_bipolar10; - printk(KERN_INFO "10.1V]: "); - } - s->len_chanlist = 1; - s->insn_read = mpc624_ai_rinsn; - - printk(KERN_INFO "attached\n"); - - return 1; -} + unsigned char status; -static int mpc624_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: mpc624: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, MPC624_SIZE); - - return 0; + status = inb(dev->iobase + MPC624_ADC); + if ((status & MPC624_ADBUSY) == 0) + return 0; + return -EBUSY; } -/* Timeout 200ms */ -#define TIMEOUT 200 - static int mpc624_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct mpc624_private *devpriv = dev->private; int n, i; unsigned long int data_in, data_out; - unsigned char ucPort; + int ret; /* * WARNING: * We always write 0 to GNSWA bit, so the channel range is +-/10.1Vdc */ outb(insn->chanspec, dev->iobase + MPC624_GNMUXCH); -/* printk("Channel %d:\n", insn->chanspec); */ - if (!insn->n) { - printk(KERN_INFO "MPC624: Warning, no data to acquire\n"); - return 0; - } for (n = 0; n < insn->n; n++) { /* Trigger the conversion */ @@ -305,18 +180,10 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, udelay(1); /* Wait for the conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - ucPort = inb(dev->iobase + MPC624_ADC); - if (ucPort & MPC624_ADBUSY) - udelay(1000); - else - break; - } - if (i == TIMEOUT) { - printk(KERN_ERR "MPC624: timeout (%dms)\n", TIMEOUT); - data[n] = 0; - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, mpc624_ai_eoc, 0); + if (ret) + return ret; + /* Start reading data */ data_in = 0; data_out = devpriv->ulConvertionRate; @@ -375,11 +242,11 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, */ if (data_in & MPC624_EOC_BIT) - printk(KERN_INFO "MPC624:EOC bit is set (data_in=%lu)!", - data_in); + dev_dbg(dev->class_dev, + "EOC bit is set (data_in=%lu)!", data_in); if (data_in & MPC624_DMY_BIT) - printk(KERN_INFO "MPC624:DMY bit is set (data_in=%lu)!", - data_in); + dev_dbg(dev->class_dev, + "DMY bit is set (data_in=%lu)!", data_in); if (data_in & MPC624_SGN_BIT) { /* Volatge is positive */ /* * comedi operates on unsigned numbers, so mask off EOC @@ -406,18 +273,88 @@ static int mpc624_ai_rinsn(struct comedi_device *dev, return n; } -static int __init driver_mpc624_init_module(void) +static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - return comedi_driver_register(&driver_mpc624); -} + struct mpc624_private *devpriv; + struct comedi_subdevice *s; + int ret; -static void __exit driver_mpc624_cleanup_module(void) -{ - comedi_driver_unregister(&driver_mpc624); + ret = comedi_request_region(dev, it->options[0], MPC624_SIZE); + if (ret) + return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + switch (it->options[1]) { + case 0: + devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; + break; + case 1: + devpriv->ulConvertionRate = MPC624_SPEED_1_76_kHz; + break; + case 2: + devpriv->ulConvertionRate = MPC624_SPEED_880_Hz; + break; + case 3: + devpriv->ulConvertionRate = MPC624_SPEED_440_Hz; + break; + case 4: + devpriv->ulConvertionRate = MPC624_SPEED_220_Hz; + break; + case 5: + devpriv->ulConvertionRate = MPC624_SPEED_110_Hz; + break; + case 6: + devpriv->ulConvertionRate = MPC624_SPEED_55_Hz; + break; + case 7: + devpriv->ulConvertionRate = MPC624_SPEED_27_5_Hz; + break; + case 8: + devpriv->ulConvertionRate = MPC624_SPEED_13_75_Hz; + break; + case 9: + devpriv->ulConvertionRate = MPC624_SPEED_6_875_Hz; + break; + default: + devpriv->ulConvertionRate = MPC624_SPEED_3_52_kHz; + } + + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + s->n_chan = 8; + switch (it->options[1]) { + default: + s->maxdata = 0x3FFFFFFF; + } + + switch (it->options[1]) { + case 0: + s->range_table = &range_mpc624_bipolar1; + break; + default: + s->range_table = &range_mpc624_bipolar10; + } + s->len_chanlist = 1; + s->insn_read = mpc624_ai_rinsn; + + return 0; } -module_init(driver_mpc624_init_module); -module_exit(driver_mpc624_cleanup_module); +static struct comedi_driver mpc624_driver = { + .driver_name = "mpc624", + .module = THIS_MODULE, + .attach = mpc624_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(mpc624_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c deleted file mode 100644 index 5f6816a3fe8..00000000000 --- a/drivers/staging/comedi/drivers/mpc8260cpm.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - comedi/drivers/mpc8260.c - driver for digital I/O pins on the MPC 8260 CPM module - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: mpc8260cpm -Description: MPC8260 CPM module generic digital I/O lines -Devices: [Motorola] MPC8260 CPM (mpc8260cpm) -Author: ds -Status: experimental -Updated: Sat, 16 Mar 2002 17:34:48 -0800 - -This driver is specific to the Motorola MPC8260 processor, allowing -you to access the processor's generic digital I/O lines. - -It is apparently missing some code. -*/ - -#include "../comedidev.h" - -extern unsigned long mpc8260_dio_reserved[4]; - -struct mpc8260cpm_private { - - int data; - -}; - -#define devpriv ((struct mpc8260cpm_private *)dev->private) - -static int mpc8260cpm_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int mpc8260cpm_detach(struct comedi_device *dev); -static struct comedi_driver driver_mpc8260cpm = { - .driver_name = "mpc8260cpm", - .module = THIS_MODULE, - .attach = mpc8260cpm_attach, - .detach = mpc8260cpm_detach, -}; - -static int __init driver_mpc8260cpm_init_module(void) -{ - return comedi_driver_register(&driver_mpc8260cpm); -} - -static void __exit driver_mpc8260cpm_cleanup_module(void) -{ - comedi_driver_unregister(&driver_mpc8260cpm); -} - -module_init(driver_mpc8260cpm_init_module); -module_exit(driver_mpc8260cpm_cleanup_module); - -static int mpc8260cpm_dio_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int mpc8260cpm_dio_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int mpc8260cpm_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int i; - - printk("comedi%d: mpc8260cpm: ", dev->minor); - - dev->board_ptr = mpc8260cpm_boards + dev->board; - - dev->board_name = thisboard->name; - - if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - for (i = 0; i < 4; i++) { - s = dev->subdevices + i; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 32; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_config = mpc8260cpm_dio_config; - s->insn_bits = mpc8260cpm_dio_bits; - } - - return 1; -} - -static int mpc8260cpm_detach(struct comedi_device *dev) -{ - printk("comedi%d: mpc8260cpm: remove\n", dev->minor); - - return 0; -} - -static unsigned long *cpm_pdat(int port) -{ - switch (port) { - case 0: - return &io->iop_pdata; - case 1: - return &io->iop_pdatb; - case 2: - return &io->iop_pdatc; - case 3: - return &io->iop_pdatd; - } -} - -static int mpc8260cpm_dio_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int n; - unsigned int d; - unsigned int mask; - int port; - - port = (int)s->private; - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & cpm_reserved_bits[port]) { - return -EINVAL; - } - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } - - switch (port) { - case 0: - return &io->iop_pdira; - case 1: - return &io->iop_pdirb; - case 2: - return &io->iop_pdirc; - case 3: - return &io->iop_pdird; - } - - return 1; -} - -static int mpc8260cpm_dio_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int port; - unsigned long *p; - - p = cpm_pdat((int)s->private); - - return 2; -} diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index dace902d3bc..b74b9e9bfd4 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: multiq3 @@ -29,11 +24,10 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3) */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> - #define MULTIQ3_SIZE 16 /* @@ -83,62 +77,48 @@ Devices: [Quanser Consulting] MultiQ-3 (multiq3) #define MULTIQ3_TIMEOUT 30 -static int multiq3_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int multiq3_detach(struct comedi_device *dev); -static struct comedi_driver driver_multiq3 = { - .driver_name = "multiq3", - .module = THIS_MODULE, - .attach = multiq3_attach, - .detach = multiq3_detach, +struct multiq3_private { + unsigned int ao_readback[2]; }; -static int __init driver_multiq3_init_module(void) +static int multiq3_ai_status(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - return comedi_driver_register(&driver_multiq3); -} + unsigned int status; -static void __exit driver_multiq3_cleanup_module(void) -{ - comedi_driver_unregister(&driver_multiq3); + status = inw(dev->iobase + MULTIQ3_STATUS); + if (status & context) + return 0; + return -EBUSY; } -module_init(driver_multiq3_init_module); -module_exit(driver_multiq3_cleanup_module); - -struct multiq3_private { - unsigned int ao_readback[2]; -}; -#define devpriv ((struct multiq3_private *)dev->private) - static int multiq3_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i, n; + int n; int chan; unsigned int hi, lo; + int ret; chan = CR_CHAN(insn->chanspec); outw(MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3), dev->iobase + MULTIQ3_CONTROL); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC); + if (ret) + return ret; for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + MULTIQ3_AD_CS); - for (i = 0; i < MULTIQ3_TIMEOUT; i++) { - if (inw(dev->iobase + - MULTIQ3_STATUS) & MULTIQ3_STATUS_EOC_I) - break; - } - if (i == MULTIQ3_TIMEOUT) - return -ETIMEDOUT; + + ret = comedi_timeout(dev, s, insn, multiq3_ai_status, + MULTIQ3_STATUS_EOC_I); + if (ret) + return ret; hi = inb(dev->iobase + MULTIQ3_AD_CS); lo = inb(dev->iobase + MULTIQ3_AD_CS); @@ -152,6 +132,7 @@ 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); @@ -165,6 +146,7 @@ static int multiq3_ao_insn_write(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); @@ -184,28 +166,22 @@ static int multiq3_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - data[1] = inw(dev->iobase + MULTIQ3_DIGIN_PORT); - return 2; + return insn->n; } static int multiq3_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - outw(s->state, dev->iobase + MULTIQ3_DIGOUT_PORT); + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + MULTIQ3_DIGOUT_PORT); data[1] = s->state; - return 2; + return insn->n; } static int multiq3_encoder_insn_read(struct comedi_device *dev, @@ -233,8 +209,10 @@ static int multiq3_encoder_insn_read(struct comedi_device *dev, static void encoder_reset(struct comedi_device *dev) { + struct comedi_subdevice *s = &dev->subdevices[4]; int chan; - for (chan = 0; chan < dev->subdevices[4].n_chan; chan++) { + + for (chan = 0; chan < s->n_chan; chan++) { int control = MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3); outw(control, dev->iobase + MULTIQ3_CONTROL); @@ -248,45 +226,26 @@ static void encoder_reset(struct comedi_device *dev) } } -/* - options[0] - I/O port - options[1] - irq - options[2] - number of encoder chips installed - */ - static int multiq3_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int result = 0; - unsigned long iobase; - unsigned int irq; + struct multiq3_private *devpriv; struct comedi_subdevice *s; + int ret; - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: multiq3: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, MULTIQ3_SIZE, "multiq3")) { - printk(KERN_ERR "comedi%d: I/O port conflict\n", dev->minor); - return -EIO; - } + ret = comedi_request_region(dev, it->options[0], MULTIQ3_SIZE); + if (ret) + return ret; - dev->iobase = iobase; + ret = comedi_alloc_subdevices(dev, 5); + if (ret) + return ret; - irq = it->options[1]; - if (irq) - printk(KERN_WARNING "comedi%d: irq = %u ignored\n", - dev->minor, irq); - else - printk(KERN_WARNING "comedi%d: no irq\n", dev->minor); - dev->board_name = "multiq3"; - result = alloc_subdevices(dev, 5); - if (result < 0) - return result; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - result = alloc_private(dev, sizeof(struct multiq3_private)); - if (result < 0) - return result; - - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -295,7 +254,7 @@ static int multiq3_attach(struct comedi_device *dev, s->maxdata = 0x1fff; s->range_table = &range_bipolar5; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -305,7 +264,7 @@ static int multiq3_attach(struct comedi_device *dev, s->maxdata = 0xfff; s->range_table = &range_bipolar5; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* di subdevice */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -314,7 +273,7 @@ static int multiq3_attach(struct comedi_device *dev, s->maxdata = 1; s->range_table = &range_digital; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* do subdevice */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -324,7 +283,7 @@ static int multiq3_attach(struct comedi_device *dev, s->range_table = &range_digital; s->state = 0; - s = dev->subdevices + 4; + s = &dev->subdevices[4]; /* encoder (counter) subdevice */ s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_LSAMPL; @@ -338,17 +297,13 @@ static int multiq3_attach(struct comedi_device *dev, return 0; } -static int multiq3_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: multiq3: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, MULTIQ3_SIZE); - if (dev->irq) - free_irq(dev->irq, dev); - - return 0; -} +static struct comedi_driver multiq3_driver = { + .driver_name = "multiq3", + .module = THIS_MODULE, + .attach = multiq3_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(multiq3_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index 54741c9e1af..c8b1fa793a3 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -1,237 +1,227 @@ /* - comedi/drivers/ni_6527.c - driver for National Instruments PCI-6527 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: ni_6527 -Description: National Instruments 6527 -Author: ds -Status: works -Devices: [National Instruments] PCI-6527 (ni6527), PXI-6527 -Updated: Sat, 25 Jan 2003 13:24:40 -0800 - - -*/ + * ni_6527.c + * Comedi driver for National Instruments PCI-6527 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999,2002,2003 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. + */ /* - Manuals (available from ftp://ftp.natinst.com/support/manuals) - - 370106b.pdf 6527 Register Level Programmer Manual - + * Driver: ni_6527 + * Description: National Instruments 6527 + * Devices: (National Instruments) PCI-6527 [pci-6527] + * (National Instruments) PXI-6527 [pxi-6527] + * Author: David A. Schleef <ds@schleef.org> + * Updated: Sat, 25 Jan 2003 13:24:40 -0800 + * Status: works + * + * Configuration Options: not applicable, uses PCI auto config */ -#define DEBUG 1 -#define DEBUG_FLAGS - +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> + #include "../comedidev.h" -#include "mite.h" - -#define NI6527_DIO_SIZE 4096 -#define NI6527_MITE_SIZE 4096 - -#define Port_Register(x) (0x00+(x)) -#define ID_Register 0x06 - -#define Clear_Register 0x07 -#define ClrEdge 0x08 -#define ClrOverflow 0x04 -#define ClrFilter 0x02 -#define ClrInterval 0x01 - -#define Filter_Interval(x) (0x08+(x)) -#define Filter_Enable(x) (0x0c+(x)) - -#define Change_Status 0x14 -#define MasterInterruptStatus 0x04 -#define Overflow 0x02 -#define EdgeStatus 0x01 - -#define Master_Interrupt_Control 0x15 -#define FallingEdgeIntEnable 0x10 -#define RisingEdgeIntEnable 0x08 -#define MasterInterruptEnable 0x04 -#define OverflowIntEnable 0x02 -#define EdgeIntEnable 0x01 - -#define Rising_Edge_Detection_Enable(x) (0x018+(x)) -#define Falling_Edge_Detection_Enable(x) (0x020+(x)) - -static int ni6527_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int ni6527_detach(struct comedi_device *dev); -static struct comedi_driver driver_ni6527 = { - .driver_name = "ni6527", - .module = THIS_MODULE, - .attach = ni6527_attach, - .detach = ni6527_detach, +#include "comedi_fc.h" + +/* + * PCI BAR1 - Register memory map + * + * Manuals (available from ftp://ftp.natinst.com/support/manuals) + * 370106b.pdf 6527 Register Level Programmer Manual + */ +#define NI6527_DI_REG(x) (0x00 + (x)) +#define NI6527_DO_REG(x) (0x03 + (x)) +#define NI6527_ID_REG 0x06 +#define NI6527_CLR_REG 0x07 +#define NI6527_CLR_EDGE (1 << 3) +#define NI6527_CLR_OVERFLOW (1 << 2) +#define NI6527_CLR_FILT (1 << 1) +#define NI6527_CLR_INTERVAL (1 << 0) +#define NI6527_CLR_IRQS (NI6527_CLR_EDGE | NI6527_CLR_OVERFLOW) +#define NI6527_CLR_RESET_FILT (NI6527_CLR_FILT | NI6527_CLR_INTERVAL) +#define NI6527_FILT_INTERVAL_REG(x) (0x08 + (x)) +#define NI6527_FILT_ENA_REG(x) (0x0c + (x)) +#define NI6527_STATUS_REG 0x14 +#define NI6527_STATUS_IRQ (1 << 2) +#define NI6527_STATUS_OVERFLOW (1 << 1) +#define NI6527_STATUS_EDGE (1 << 0) +#define NI6527_CTRL_REG 0x15 +#define NI6527_CTRL_FALLING (1 << 4) +#define NI6527_CTRL_RISING (1 << 3) +#define NI6527_CTRL_IRQ (1 << 2) +#define NI6527_CTRL_OVERFLOW (1 << 1) +#define NI6527_CTRL_EDGE (1 << 0) +#define NI6527_CTRL_DISABLE_IRQS 0 +#define NI6527_CTRL_ENABLE_IRQS (NI6527_CTRL_FALLING | \ + NI6527_CTRL_RISING | \ + NI6527_CTRL_IRQ | NI6527_CTRL_EDGE) +#define NI6527_RISING_EDGE_REG(x) (0x18 + (x)) +#define NI6527_FALLING_EDGE_REG(x) (0x20 + (x)) + +enum ni6527_boardid { + BOARD_PCI6527, + BOARD_PXI6527, }; struct ni6527_board { - - int dev_id; const char *name; }; static const struct ni6527_board ni6527_boards[] = { - { - .dev_id = 0x2b20, - .name = "pci-6527", - }, - { - .dev_id = 0x2b10, - .name = "pxi-6527", - }, -}; - -#define n_ni6527_boards ARRAY_SIZE(ni6527_boards) -#define this_board ((const struct ni6527_board *)dev->board_ptr) - -static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b10)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b20)}, - {0} + [BOARD_PCI6527] = { + .name = "pci-6527", + }, + [BOARD_PXI6527] = { + .name = "pxi-6527", + }, }; -MODULE_DEVICE_TABLE(pci, ni6527_pci_table); - struct ni6527_private { - struct mite_struct *mite; + void __iomem *mmio_base; unsigned int filter_interval; unsigned int filter_enable; }; -#define devpriv ((struct ni6527_private *)dev->private) +static void ni6527_set_filter_interval(struct comedi_device *dev, + unsigned int val) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + if (val != devpriv->filter_interval) { + writeb(val & 0xff, mmio + NI6527_FILT_INTERVAL_REG(0)); + writeb((val >> 8) & 0xff, mmio + NI6527_FILT_INTERVAL_REG(1)); + writeb((val >> 16) & 0x0f, mmio + NI6527_FILT_INTERVAL_REG(2)); + + writeb(NI6527_CLR_INTERVAL, mmio + NI6527_CLR_REG); + + devpriv->filter_interval = val; + } +} -static int ni6527_find_device(struct comedi_device *dev, int bus, int slot); +static void ni6527_set_filter_enable(struct comedi_device *dev, + unsigned int val) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + writeb(val & 0xff, mmio + NI6527_FILT_ENA_REG(0)); + writeb((val >> 8) & 0xff, mmio + NI6527_FILT_ENA_REG(1)); + writeb((val >> 16) & 0xff, mmio + NI6527_FILT_ENA_REG(2)); +} static int ni6527_di_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + struct ni6527_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int interval; - if (insn->n != 2) - return -EINVAL; - - if (data[0] != INSN_CONFIG_FILTER) - return -EINVAL; - - if (data[1]) { + switch (data[0]) { + case INSN_CONFIG_FILTER: + /* + * The deglitch filter interval is specified in nanoseconds. + * The hardware supports intervals in 200ns increments. Round + * the user values up and return the actual interval. + */ interval = (data[1] + 100) / 200; data[1] = interval * 200; - if (interval != devpriv->filter_interval) { - writeb(interval & 0xff, - devpriv->mite->daq_io_addr + Filter_Interval(0)); - writeb((interval >> 8) & 0xff, - devpriv->mite->daq_io_addr + Filter_Interval(1)); - writeb((interval >> 16) & 0x0f, - devpriv->mite->daq_io_addr + Filter_Interval(2)); - - writeb(ClrInterval, - devpriv->mite->daq_io_addr + Clear_Register); - - devpriv->filter_interval = interval; + if (interval) { + ni6527_set_filter_interval(dev, interval); + devpriv->filter_enable |= 1 << chan; + } else { + devpriv->filter_enable &= ~(1 << chan); } - - devpriv->filter_enable |= 1 << chan; - } else { - devpriv->filter_enable &= ~(1 << chan); + ni6527_set_filter_enable(dev, devpriv->filter_enable); + break; + default: + return -EINVAL; } - writeb(devpriv->filter_enable, - devpriv->mite->daq_io_addr + Filter_Enable(0)); - writeb(devpriv->filter_enable >> 8, - devpriv->mite->daq_io_addr + Filter_Enable(1)); - writeb(devpriv->filter_enable >> 16, - devpriv->mite->daq_io_addr + Filter_Enable(2)); - - return 2; + return insn->n; } static int ni6527_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + unsigned int val; - data[1] = readb(devpriv->mite->daq_io_addr + Port_Register(0)); - data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(1)) << 8; - data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(2)) << 16; + val = readb(mmio + NI6527_DI_REG(0)); + val |= (readb(mmio + NI6527_DI_REG(1)) << 8); + val |= (readb(mmio + NI6527_DI_REG(2)) << 16); - return 2; + data[1] = val; + + return insn->n; } static int ni6527_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - /* The open relay state on the board cooresponds to 1, - * but in Comedi, it is represented by 0. */ - if (data[0] & 0x0000ff) { - writeb((s->state ^ 0xff), - devpriv->mite->daq_io_addr + Port_Register(3)); - } - if (data[0] & 0x00ff00) { - writeb((s->state >> 8) ^ 0xff, - devpriv->mite->daq_io_addr + Port_Register(4)); - } - if (data[0] & 0xff0000) { - writeb((s->state >> 16) ^ 0xff, - devpriv->mite->daq_io_addr + Port_Register(5)); - } + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + /* Outputs are inverted */ + unsigned int val = s->state ^ 0xffffff; + + if (mask & 0x0000ff) + writeb(val & 0xff, mmio + NI6527_DO_REG(0)); + if (mask & 0x00ff00) + writeb((val >> 8) & 0xff, mmio + NI6527_DO_REG(1)); + if (mask & 0xff0000) + writeb((val >> 16) & 0xff, mmio + NI6527_DO_REG(2)); } + data[1] = s->state; - return 2; + return insn->n; } static irqreturn_t ni6527_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 2; + struct ni6527_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + void __iomem *mmio = devpriv->mmio_base; unsigned int status; - status = readb(devpriv->mite->daq_io_addr + Change_Status); - if ((status & MasterInterruptStatus) == 0) - return IRQ_NONE; - if ((status & EdgeStatus) == 0) + status = readb(mmio + NI6527_STATUS_REG); + if (!(status & NI6527_STATUS_IRQ)) return IRQ_NONE; - writeb(ClrEdge | ClrOverflow, - devpriv->mite->daq_io_addr + Clear_Register); + if (status & NI6527_STATUS_EDGE) { + comedi_buf_put(s, 0); + s->async->events |= COMEDI_CB_EOS; + comedi_event(dev, s); + } + + writeb(NI6527_CLR_IRQS, mmio + NI6527_CLR_REG); - comedi_buf_put(s->async, 0); - s->async->events |= COMEDI_CB_EOS; - comedi_event(dev, s); return IRQ_HANDLED; } @@ -240,67 +230,31 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_OTHER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER); + 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_COUNT); if (err) return 1; - /* step 2: make sure trigger sources are unique and */ - /* are mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - - if (cmd->scan_end_arg != 1) { - cmd->scan_end_arg = 1; - err++; - } - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + 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; @@ -316,13 +270,11 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev, static int ni6527_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - /* struct comedi_cmd *cmd = &s->async->cmd; */ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; - writeb(ClrEdge | ClrOverflow, - devpriv->mite->daq_io_addr + Clear_Register); - writeb(FallingEdgeIntEnable | RisingEdgeIntEnable | - MasterInterruptEnable | EdgeIntEnable, - devpriv->mite->daq_io_addr + Master_Interrupt_Control); + writeb(NI6527_CLR_IRQS, mmio + NI6527_CLR_REG); + writeb(NI6527_CTRL_ENABLE_IRQS, mmio + NI6527_CTRL_REG); return 0; } @@ -330,7 +282,10 @@ static int ni6527_intr_cmd(struct comedi_device *dev, static int ni6527_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + writeb(NI6527_CTRL_DISABLE_IRQS, mmio + NI6527_CTRL_REG); return 0; } @@ -339,195 +294,183 @@ static int ni6527_intr_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - if (insn->n < 1) - return -EINVAL; - data[1] = 0; - return 2; + return insn->n; +} + +static void ni6527_set_edge_detection(struct comedi_device *dev, + unsigned int rising, + unsigned int falling) +{ + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + /* enable rising-edge detection channels */ + writeb(rising & 0xff, mmio + NI6527_RISING_EDGE_REG(0)); + writeb((rising >> 8) & 0xff, mmio + NI6527_RISING_EDGE_REG(1)); + writeb((rising >> 16) & 0xff, mmio + NI6527_RISING_EDGE_REG(2)); + + /* enable falling-edge detection channels */ + writeb(falling & 0xff, mmio + NI6527_FALLING_EDGE_REG(0)); + writeb((falling >> 8) & 0xff, mmio + NI6527_FALLING_EDGE_REG(1)); + writeb((falling >> 16) & 0xff, mmio + NI6527_FALLING_EDGE_REG(2)); } static int ni6527_intr_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n < 1) - return -EINVAL; - if (data[0] != INSN_CONFIG_CHANGE_NOTIFY) + switch (data[0]) { + case INSN_CONFIG_CHANGE_NOTIFY: + /* check_insn_config_length() does not check this instruction */ + if (insn->n != 3) + return -EINVAL; + ni6527_set_edge_detection(dev, data[1], data[2]); + break; + default: return -EINVAL; + } - writeb(data[1], - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0)); - writeb(data[1] >> 8, - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(1)); - writeb(data[1] >> 16, - devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(2)); - - writeb(data[2], - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0)); - writeb(data[2] >> 8, - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(1)); - writeb(data[2] >> 16, - devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(2)); - - return 2; + return insn->n; } -static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static void ni6527_reset(struct comedi_device *dev) { + struct ni6527_private *devpriv = dev->private; + void __iomem *mmio = devpriv->mmio_base; + + /* disable deglitch filters on all channels */ + ni6527_set_filter_enable(dev, 0); + + writeb(NI6527_CLR_IRQS | NI6527_CLR_RESET_FILT, + mmio + NI6527_CLR_REG); + writeb(NI6527_CTRL_DISABLE_IRQS, mmio + NI6527_CTRL_REG); +} + +static int ni6527_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct ni6527_board *board = NULL; + struct ni6527_private *devpriv; struct comedi_subdevice *s; int ret; - printk(KERN_INFO "comedi%d: ni6527\n", dev->minor); + if (context < ARRAY_SIZE(ni6527_boards)) + board = &ni6527_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; - ret = alloc_private(dev, sizeof(struct ni6527_private)); - if (ret < 0) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = ni6527_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) + ret = comedi_pci_enable(dev); + if (ret) return ret; - ret = mite_setup(devpriv->mite); - if (ret < 0) { - printk(KERN_ERR "comedi: error setting up mite\n"); - return ret; - } + devpriv->mmio_base = pci_ioremap_bar(pcidev, 1); + if (!devpriv->mmio_base) + return -ENOMEM; - dev->board_name = this_board->name; - printk(KERN_INFO "comedi board: %s, ID=0x%02x\n", dev->board_name, - readb(devpriv->mite->daq_io_addr + ID_Register)); + /* make sure this is actually a 6527 device */ + if (readb(devpriv->mmio_base + NI6527_ID_REG) != 0x27) + return -ENODEV; - ret = alloc_subdevices(dev, 3); - if (ret < 0) + ni6527_reset(dev); + + ret = request_irq(pcidev->irq, ni6527_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) return ret; - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 24; - s->range_table = &range_digital; - s->maxdata = 1; - s->insn_config = ni6527_di_insn_config; - s->insn_bits = ni6527_di_insn_bits; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 24; - s->range_table = &range_unknown; /* FIXME: actually conductance */ - s->maxdata = 1; - s->insn_bits = ni6527_do_insn_bits; - - s = dev->subdevices + 2; - dev->read_subdev = s; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = 1; - s->range_table = &range_unknown; - s->maxdata = 1; - s->do_cmdtest = ni6527_intr_cmdtest; - s->do_cmd = ni6527_intr_cmd; - s->cancel = ni6527_intr_cancel; - s->insn_bits = ni6527_intr_insn_bits; - s->insn_config = ni6527_intr_insn_config; - - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0)); - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(1)); - writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(2)); - - writeb(ClrEdge | ClrOverflow | ClrFilter | ClrInterval, - devpriv->mite->daq_io_addr + Clear_Register); - writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); - - ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt, - IRQF_SHARED, "ni6527", dev); - if (ret < 0) - printk(KERN_WARNING "comedi i6527 irq not available\n"); - else - dev->irq = mite_irq(devpriv->mite); + /* Digital Input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_config = ni6527_di_insn_config; + s->insn_bits = ni6527_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ni6527_do_insn_bits; + + /* Edge detection 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->insn_config = ni6527_intr_insn_config; + s->insn_bits = ni6527_intr_insn_bits; + s->len_chanlist = 1; + s->do_cmdtest = ni6527_intr_cmdtest; + s->do_cmd = ni6527_intr_cmd; + s->cancel = ni6527_intr_cancel; + } else { + s->type = COMEDI_SUBD_UNUSED; + } return 0; } -static int ni6527_detach(struct comedi_device *dev) +static void ni6527_detach(struct comedi_device *dev) { - if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) - writeb(0x00, - devpriv->mite->daq_io_addr + Master_Interrupt_Control); + struct ni6527_private *devpriv = dev->private; + if (devpriv && devpriv->mmio_base) + ni6527_reset(dev); if (dev->irq) free_irq(dev->irq, dev); - - if (devpriv && devpriv->mite) - mite_unsetup(devpriv->mite); - - return 0; -} - -static int ni6527_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < n_ni6527_boards; i++) { - if (mite_device_id(mite) == ni6527_boards[i].dev_id) { - dev->board_ptr = ni6527_boards + i; - devpriv->mite = mite; - return 0; - } - } - } - printk(KERN_ERR "comedi 6527: no device found\n"); - mite_list_devices(); - return -EIO; + comedi_pci_disable(dev); } -static int __devinit driver_ni6527_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_ni6527.driver_name); -} - -static void __devexit driver_ni6527_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_ni6527_pci_driver = { - .id_table = ni6527_pci_table, - .probe = &driver_ni6527_pci_probe, - .remove = __devexit_p(&driver_ni6527_pci_remove) +static struct comedi_driver ni6527_driver = { + .driver_name = "ni_6527", + .module = THIS_MODULE, + .auto_attach = ni6527_auto_attach, + .detach = ni6527_detach, }; -static int __init driver_ni6527_init_module(void) +static int ni6527_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_ni6527); - if (retval < 0) - return retval; - - driver_ni6527_pci_driver.name = (char *)driver_ni6527.driver_name; - return pci_register_driver(&driver_ni6527_pci_driver); + return comedi_pci_auto_config(dev, &ni6527_driver, id->driver_data); } -static void __exit driver_ni6527_cleanup_module(void) -{ - pci_unregister_driver(&driver_ni6527_pci_driver); - comedi_driver_unregister(&driver_ni6527); -} +static const struct pci_device_id ni6527_pci_table[] = { + { PCI_VDEVICE(NI, 0x2b10), BOARD_PXI6527 }, + { PCI_VDEVICE(NI, 0x2b20), BOARD_PCI6527 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ni6527_pci_table); -module_init(driver_ni6527_init_module); -module_exit(driver_ni6527_cleanup_module); +static struct pci_driver ni6527_pci_driver = { + .name = "ni_6527", + .id_table = ni6527_pci_table, + .probe = ni6527_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for National Instruments PCI-6527"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index 403fc0997d3..9a139d6b8ef 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -17,11 +17,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_65xx @@ -48,13 +43,13 @@ except maybe the 6514. */ -#define _GNU_SOURCE -#define DEBUG 1 -#define DEBUG_FLAGS +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> -#include <linux/slab.h> + #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" #define NI6514_DIO_SIZE 4096 @@ -109,19 +104,32 @@ static inline unsigned Filter_Enable(unsigned port) #define OverflowIntEnable 0x02 #define EdgeIntEnable 0x01 -static int ni_65xx_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int ni_65xx_detach(struct comedi_device *dev); -static struct comedi_driver driver_ni_65xx = { - .driver_name = "ni_65xx", - .module = THIS_MODULE, - .attach = ni_65xx_attach, - .detach = ni_65xx_detach, +enum ni_65xx_boardid { + BOARD_PCI6509, + BOARD_PXI6509, + BOARD_PCI6510, + BOARD_PCI6511, + BOARD_PXI6511, + BOARD_PCI6512, + BOARD_PXI6512, + BOARD_PCI6513, + BOARD_PXI6513, + BOARD_PCI6514, + BOARD_PXI6514, + BOARD_PCI6515, + BOARD_PXI6515, + BOARD_PCI6516, + BOARD_PCI6517, + BOARD_PCI6518, + BOARD_PCI6519, + BOARD_PCI6520, + BOARD_PCI6521, + BOARD_PXI6521, + BOARD_PCI6528, + BOARD_PXI6528, }; struct ni_65xx_board { - - int dev_id; const char *name; unsigned num_dio_ports; unsigned num_di_ports; @@ -130,130 +138,117 @@ struct ni_65xx_board { }; static const struct ni_65xx_board ni_65xx_boards[] = { - { - .dev_id = 0x7085, - .name = "pci-6509", - .num_dio_ports = 12, - .invert_outputs = 0}, - { - .dev_id = 0x1710, - .name = "pxi-6509", - .num_dio_ports = 12, - .invert_outputs = 0}, - { - .dev_id = 0x7124, - .name = "pci-6510", - .num_di_ports = 4}, - { - .dev_id = 0x70c3, - .name = "pci-6511", - .num_di_ports = 8}, - { - .dev_id = 0x70d3, - .name = "pxi-6511", - .num_di_ports = 8}, - { - .dev_id = 0x70cc, - .name = "pci-6512", - .num_do_ports = 8}, - { - .dev_id = 0x70d2, - .name = "pxi-6512", - .num_do_ports = 8}, - { - .dev_id = 0x70c8, - .name = "pci-6513", - .num_do_ports = 8, - .invert_outputs = 1}, - { - .dev_id = 0x70d1, - .name = "pxi-6513", - .num_do_ports = 8, - .invert_outputs = 1}, - { - .dev_id = 0x7088, - .name = "pci-6514", - .num_di_ports = 4, - .num_do_ports = 4, - .invert_outputs = 1}, - { - .dev_id = 0x70CD, - .name = "pxi-6514", - .num_di_ports = 4, - .num_do_ports = 4, - .invert_outputs = 1}, - { - .dev_id = 0x7087, - .name = "pci-6515", - .num_di_ports = 4, - .num_do_ports = 4, - .invert_outputs = 1}, - { - .dev_id = 0x70c9, - .name = "pxi-6515", - .num_di_ports = 4, - .num_do_ports = 4, - .invert_outputs = 1}, - { - .dev_id = 0x7125, - .name = "pci-6516", - .num_do_ports = 4, - .invert_outputs = 1}, - { - .dev_id = 0x7126, - .name = "pci-6517", - .num_do_ports = 4, - .invert_outputs = 1}, - { - .dev_id = 0x7127, - .name = "pci-6518", - .num_di_ports = 2, - .num_do_ports = 2, - .invert_outputs = 1}, - { - .dev_id = 0x7128, - .name = "pci-6519", - .num_di_ports = 2, - .num_do_ports = 2, - .invert_outputs = 1}, - { - .dev_id = 0x71c5, - .name = "pci-6520", - .num_di_ports = 1, - .num_do_ports = 1, - }, - { - .dev_id = 0x718b, - .name = "pci-6521", - .num_di_ports = 1, - .num_do_ports = 1, - }, - { - .dev_id = 0x718c, - .name = "pxi-6521", - .num_di_ports = 1, - .num_do_ports = 1, - }, - { - .dev_id = 0x70a9, - .name = "pci-6528", - .num_di_ports = 3, - .num_do_ports = 3, - }, - { - .dev_id = 0x7086, - .name = "pxi-6528", - .num_di_ports = 3, - .num_do_ports = 3, - }, + [BOARD_PCI6509] = { + .name = "pci-6509", + .num_dio_ports = 12, + }, + [BOARD_PXI6509] = { + .name = "pxi-6509", + .num_dio_ports = 12, + }, + [BOARD_PCI6510] = { + .name = "pci-6510", + .num_di_ports = 4, + }, + [BOARD_PCI6511] = { + .name = "pci-6511", + .num_di_ports = 8, + }, + [BOARD_PXI6511] = { + .name = "pxi-6511", + .num_di_ports = 8, + }, + [BOARD_PCI6512] = { + .name = "pci-6512", + .num_do_ports = 8, + }, + [BOARD_PXI6512] = { + .name = "pxi-6512", + .num_do_ports = 8, + }, + [BOARD_PCI6513] = { + .name = "pci-6513", + .num_do_ports = 8, + .invert_outputs = 1, + }, + [BOARD_PXI6513] = { + .name = "pxi-6513", + .num_do_ports = 8, + .invert_outputs = 1, + }, + [BOARD_PCI6514] = { + .name = "pci-6514", + .num_di_ports = 4, + .num_do_ports = 4, + .invert_outputs = 1, + }, + [BOARD_PXI6514] = { + .name = "pxi-6514", + .num_di_ports = 4, + .num_do_ports = 4, + .invert_outputs = 1, + }, + [BOARD_PCI6515] = { + .name = "pci-6515", + .num_di_ports = 4, + .num_do_ports = 4, + .invert_outputs = 1, + }, + [BOARD_PXI6515] = { + .name = "pxi-6515", + .num_di_ports = 4, + .num_do_ports = 4, + .invert_outputs = 1, + }, + [BOARD_PCI6516] = { + .name = "pci-6516", + .num_do_ports = 4, + .invert_outputs = 1, + }, + [BOARD_PCI6517] = { + .name = "pci-6517", + .num_do_ports = 4, + .invert_outputs = 1, + }, + [BOARD_PCI6518] = { + .name = "pci-6518", + .num_di_ports = 2, + .num_do_ports = 2, + .invert_outputs = 1, + }, + [BOARD_PCI6519] = { + .name = "pci-6519", + .num_di_ports = 2, + .num_do_ports = 2, + .invert_outputs = 1, + }, + [BOARD_PCI6520] = { + .name = "pci-6520", + .num_di_ports = 1, + .num_do_ports = 1, + }, + [BOARD_PCI6521] = { + .name = "pci-6521", + .num_di_ports = 1, + .num_do_ports = 1, + }, + [BOARD_PXI6521] = { + .name = "pxi-6521", + .num_di_ports = 1, + .num_do_ports = 1, + }, + [BOARD_PCI6528] = { + .name = "pci-6528", + .num_di_ports = 3, + .num_do_ports = 3, + }, + [BOARD_PXI6528] = { + .name = "pxi-6528", + .num_di_ports = 3, + .num_do_ports = 3, + }, }; -#define n_ni_65xx_boards ARRAY_SIZE(ni_65xx_boards) -static inline const struct ni_65xx_board *board(struct comedi_device *dev) -{ - return dev->board_ptr; -} - static inline unsigned ni_65xx_port_by_channel(unsigned channel) { return channel / ni_65xx_channels_per_port; @@ -265,34 +260,6 @@ static inline unsigned ni_65xx_total_num_ports(const struct ni_65xx_board return board->num_dio_ports + board->num_di_ports + board->num_do_ports; } -static DEFINE_PCI_DEVICE_TABLE(ni_65xx_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1710)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7085)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7086)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7087)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7088)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70a9)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c3)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c8)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c9)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70cc)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70CD)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70d1)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70d2)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70d3)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7124)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7125)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7126)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7127)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x7128)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x718b)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x718c)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71c5)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, ni_65xx_pci_table); - struct ni_65xx_private { struct mite_struct *mite; unsigned int filter_interval; @@ -301,11 +268,6 @@ struct ni_65xx_private { unsigned short dio_direction[NI_65XX_MAX_NUM_PORTS]; }; -static inline struct ni_65xx_private *private(struct comedi_device *dev) -{ - return dev->private; -} - struct ni_65xx_subdevice_private { unsigned base_port; }; @@ -316,21 +278,11 @@ static inline struct ni_65xx_subdevice_private *sprivate(struct comedi_subdevice return subdev->private; } -static struct ni_65xx_subdevice_private *ni_65xx_alloc_subdevice_private(void) -{ - struct ni_65xx_subdevice_private *subdev_private = - kzalloc(sizeof(struct ni_65xx_subdevice_private), GFP_KERNEL); - if (subdev_private == NULL) - return NULL; - return subdev_private; -} - -static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot); - static int ni_65xx_config_filter(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_65xx_private *devpriv = dev->private; const unsigned chan = CR_CHAN(insn->chanspec); const unsigned port = sprivate(s)->base_port + ni_65xx_port_by_channel(chan); @@ -347,22 +299,22 @@ static int ni_65xx_config_filter(struct comedi_device *dev, interval = max_filter_interval; data[1] = interval * filter_resolution_ns; - if (interval != private(dev)->filter_interval) { + if (interval != devpriv->filter_interval) { writeb(interval, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Filter_Interval); - private(dev)->filter_interval = interval; + devpriv->filter_interval = interval; } - private(dev)->filter_enable[port] |= + devpriv->filter_enable[port] |= 1 << (chan % ni_65xx_channels_per_port); } else { - private(dev)->filter_enable[port] &= + devpriv->filter_enable[port] &= ~(1 << (chan % ni_65xx_channels_per_port)); } - writeb(private(dev)->filter_enable[port], - private(dev)->mite->daq_io_addr + Filter_Enable(port)); + writeb(devpriv->filter_enable[port], + devpriv->mite->daq_io_addr + Filter_Enable(port)); return 2; } @@ -371,6 +323,7 @@ static int ni_65xx_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_65xx_private *devpriv = dev->private; unsigned port; if (insn->n < 1) @@ -384,21 +337,21 @@ static int ni_65xx_dio_insn_config(struct comedi_device *dev, case INSN_CONFIG_DIO_OUTPUT: if (s->type != COMEDI_SUBD_DIO) return -EINVAL; - private(dev)->dio_direction[port] = COMEDI_OUTPUT; - writeb(0, private(dev)->mite->daq_io_addr + Port_Select(port)); + devpriv->dio_direction[port] = COMEDI_OUTPUT; + writeb(0, devpriv->mite->daq_io_addr + Port_Select(port)); return 1; break; case INSN_CONFIG_DIO_INPUT: if (s->type != COMEDI_SUBD_DIO) return -EINVAL; - private(dev)->dio_direction[port] = COMEDI_INPUT; - writeb(1, private(dev)->mite->daq_io_addr + Port_Select(port)); + devpriv->dio_direction[port] = COMEDI_INPUT; + writeb(1, devpriv->mite->daq_io_addr + Port_Select(port)); return 1; break; case INSN_CONFIG_DIO_QUERY: if (s->type != COMEDI_SUBD_DIO) return -EINVAL; - data[1] = private(dev)->dio_direction[port]; + data[1] = devpriv->dio_direction[port]; return insn->n; break; default: @@ -411,29 +364,25 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - unsigned base_bitfield_channel; - const unsigned max_ports_per_bitfield = 5; + const struct ni_65xx_board *board = comedi_board(dev); + struct ni_65xx_private *devpriv = dev->private; + int base_bitfield_channel; unsigned read_bits = 0; - unsigned j; - if (insn->n != 2) - return -EINVAL; + int last_port_offset = ni_65xx_port_by_channel(s->n_chan - 1); + int port_offset; + base_bitfield_channel = CR_CHAN(insn->chanspec); - for (j = 0; j < max_ports_per_bitfield; ++j) { - const unsigned port_offset = - ni_65xx_port_by_channel(base_bitfield_channel) + j; - const unsigned port = - sprivate(s)->base_port + port_offset; - unsigned base_port_channel; + for (port_offset = ni_65xx_port_by_channel(base_bitfield_channel); + port_offset <= last_port_offset; port_offset++) { + unsigned port = sprivate(s)->base_port + port_offset; + int base_port_channel = port_offset * ni_65xx_channels_per_port; unsigned port_mask, port_data, port_read_bits; - int bitshift; - if (port >= ni_65xx_total_num_ports(board(dev))) + int bitshift = base_port_channel - base_bitfield_channel; + + if (bitshift >= 32) break; - base_port_channel = port_offset * ni_65xx_channels_per_port; port_mask = data[0]; port_data = data[1]; - bitshift = base_port_channel - base_bitfield_channel; - if (bitshift >= 32 || bitshift <= -32) - break; if (bitshift > 0) { port_mask >>= bitshift; port_data >>= bitshift; @@ -445,21 +394,19 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev, port_data &= 0xff; if (port_mask) { unsigned bits; - private(dev)->output_bits[port] &= ~port_mask; - private(dev)->output_bits[port] |= + devpriv->output_bits[port] &= ~port_mask; + devpriv->output_bits[port] |= port_data & port_mask; - bits = private(dev)->output_bits[port]; - if (board(dev)->invert_outputs) + bits = devpriv->output_bits[port]; + if (board->invert_outputs) bits = ~bits; writeb(bits, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Port_Data(port)); -/* printk("wrote 0x%x to port %i\n", bits, port); */ } port_read_bits = - readb(private(dev)->mite->daq_io_addr + Port_Data(port)); -/* printk("read 0x%x from port %i\n", port_read_bits, port); */ - if (s->type == COMEDI_SUBD_DO && board(dev)->invert_outputs) { + readb(devpriv->mite->daq_io_addr + Port_Data(port)); + if (s->type == COMEDI_SUBD_DO && board->invert_outputs) { /* Outputs inverted, so invert value read back from * DO subdevice. (Does not apply to boards with DIO * subdevice.) */ @@ -479,19 +426,20 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev, static irqreturn_t ni_65xx_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 2; + struct ni_65xx_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; unsigned int status; - status = readb(private(dev)->mite->daq_io_addr + Change_Status); + status = readb(devpriv->mite->daq_io_addr + Change_Status); if ((status & MasterInterruptStatus) == 0) return IRQ_NONE; if ((status & EdgeStatus) == 0) return IRQ_NONE; writeb(ClrEdge | ClrOverflow, - private(dev)->mite->daq_io_addr + Clear_Register); + devpriv->mite->daq_io_addr + Clear_Register); - comedi_buf_put(s->async, 0); + comedi_buf_put(s, 0); s->async->events |= COMEDI_CB_EOS; comedi_event(dev, s); return IRQ_HANDLED; @@ -502,67 +450,31 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_OTHER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER); + 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_COUNT); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - compatible */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - - if (cmd->scan_end_arg != 1) { - cmd->scan_end_arg = 1; - err++; - } - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + 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; @@ -578,13 +490,13 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev, static int ni_65xx_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - /* struct comedi_cmd *cmd = &s->async->cmd; */ + struct ni_65xx_private *devpriv = dev->private; writeb(ClrEdge | ClrOverflow, - private(dev)->mite->daq_io_addr + Clear_Register); + devpriv->mite->daq_io_addr + Clear_Register); writeb(FallingEdgeIntEnable | RisingEdgeIntEnable | MasterInterruptEnable | EdgeIntEnable, - private(dev)->mite->daq_io_addr + Master_Interrupt_Control); + devpriv->mite->daq_io_addr + Master_Interrupt_Control); return 0; } @@ -592,8 +504,9 @@ static int ni_65xx_intr_cmd(struct comedi_device *dev, static int ni_65xx_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - writeb(0x00, - private(dev)->mite->daq_io_addr + Master_Interrupt_Control); + struct ni_65xx_private *devpriv = dev->private; + + writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); return 0; } @@ -602,11 +515,8 @@ static int ni_65xx_intr_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - if (insn->n < 1) - return -EINVAL; - data[1] = 0; - return 2; + return insn->n; } static int ni_65xx_intr_insn_config(struct comedi_device *dev, @@ -614,263 +524,254 @@ static int ni_65xx_intr_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { + struct ni_65xx_private *devpriv = dev->private; + if (insn->n < 1) return -EINVAL; if (data[0] != INSN_CONFIG_CHANGE_NOTIFY) return -EINVAL; writeb(data[1], - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0)); writeb(data[1] >> 8, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x10)); writeb(data[1] >> 16, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x20)); writeb(data[1] >> 24, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0x30)); writeb(data[2], - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0)); writeb(data[2] >> 8, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x10)); writeb(data[2] >> 16, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x20)); writeb(data[2] >> 24, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0x30)); return 2; } -static int ni_65xx_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int ni_65xx_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct ni_65xx_board *board = NULL; + struct ni_65xx_private *devpriv; + struct ni_65xx_subdevice_private *spriv; struct comedi_subdevice *s; unsigned i; int ret; - printk(KERN_INFO "comedi%d: ni_65xx:", dev->minor); + if (context < ARRAY_SIZE(ni_65xx_boards)) + board = &ni_65xx_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; - ret = alloc_private(dev, sizeof(struct ni_65xx_private)); - if (ret < 0) + ret = comedi_pci_enable(dev); + if (ret) return ret; - ret = ni_65xx_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; - ret = mite_setup(private(dev)->mite); + ret = mite_setup(devpriv->mite); if (ret < 0) { - printk(KERN_WARNING "error setting up mite\n"); + dev_warn(dev->class_dev, "error setting up mite\n"); return ret; } - dev->board_name = board(dev)->name; - dev->irq = mite_irq(private(dev)->mite); - printk(KERN_INFO " %s", dev->board_name); + dev->irq = mite_irq(devpriv->mite); + dev_info(dev->class_dev, "board: %s, ID=0x%02x", dev->board_name, + readb(devpriv->mite->daq_io_addr + ID_Register)); - printk(KERN_INFO " ID=0x%02x", - readb(private(dev)->mite->daq_io_addr + ID_Register)); - - ret = alloc_subdevices(dev, 4); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - s = dev->subdevices + 0; - if (board(dev)->num_di_ports) { + s = &dev->subdevices[0]; + if (board->num_di_ports) { s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = - board(dev)->num_di_ports * ni_65xx_channels_per_port; + board->num_di_ports * ni_65xx_channels_per_port; s->range_table = &range_digital; s->maxdata = 1; s->insn_config = ni_65xx_dio_insn_config; s->insn_bits = ni_65xx_dio_insn_bits; - s->private = ni_65xx_alloc_subdevice_private(); - if (s->private == NULL) + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) return -ENOMEM; - sprivate(s)->base_port = 0; + spriv->base_port = 0; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 1; - if (board(dev)->num_do_ports) { + s = &dev->subdevices[1]; + if (board->num_do_ports) { s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = - board(dev)->num_do_ports * ni_65xx_channels_per_port; + board->num_do_ports * ni_65xx_channels_per_port; s->range_table = &range_digital; s->maxdata = 1; s->insn_bits = ni_65xx_dio_insn_bits; - s->private = ni_65xx_alloc_subdevice_private(); - if (s->private == NULL) + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) return -ENOMEM; - sprivate(s)->base_port = board(dev)->num_di_ports; + spriv->base_port = board->num_di_ports; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 2; - if (board(dev)->num_dio_ports) { + s = &dev->subdevices[2]; + if (board->num_dio_ports) { s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = - board(dev)->num_dio_ports * ni_65xx_channels_per_port; + board->num_dio_ports * ni_65xx_channels_per_port; s->range_table = &range_digital; s->maxdata = 1; s->insn_config = ni_65xx_dio_insn_config; s->insn_bits = ni_65xx_dio_insn_bits; - s->private = ni_65xx_alloc_subdevice_private(); - if (s->private == NULL) + spriv = comedi_alloc_spriv(s, sizeof(*spriv)); + if (!spriv) return -ENOMEM; - sprivate(s)->base_port = 0; - for (i = 0; i < board(dev)->num_dio_ports; ++i) { + spriv->base_port = 0; + for (i = 0; i < board->num_dio_ports; ++i) { /* configure all ports for input */ writeb(0x1, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Port_Select(i)); } } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 3; + s = &dev->subdevices[3]; dev->read_subdev = s; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_CMD_READ; s->n_chan = 1; s->range_table = &range_unknown; s->maxdata = 1; + s->len_chanlist = 1; s->do_cmdtest = ni_65xx_intr_cmdtest; s->do_cmd = ni_65xx_intr_cmd; s->cancel = ni_65xx_intr_cancel; s->insn_bits = ni_65xx_intr_insn_bits; s->insn_config = ni_65xx_intr_insn_config; - for (i = 0; i < ni_65xx_total_num_ports(board(dev)); ++i) { + for (i = 0; i < ni_65xx_total_num_ports(board); ++i) { writeb(0x00, - private(dev)->mite->daq_io_addr + Filter_Enable(i)); - if (board(dev)->invert_outputs) + devpriv->mite->daq_io_addr + Filter_Enable(i)); + if (board->invert_outputs) writeb(0x01, - private(dev)->mite->daq_io_addr + Port_Data(i)); + devpriv->mite->daq_io_addr + Port_Data(i)); else writeb(0x00, - private(dev)->mite->daq_io_addr + Port_Data(i)); + devpriv->mite->daq_io_addr + Port_Data(i)); } writeb(ClrEdge | ClrOverflow, - private(dev)->mite->daq_io_addr + Clear_Register); + devpriv->mite->daq_io_addr + Clear_Register); writeb(0x00, - private(dev)->mite->daq_io_addr + Master_Interrupt_Control); + devpriv->mite->daq_io_addr + Master_Interrupt_Control); /* Set filter interval to 0 (32bit reg) */ - writeb(0x00000000, private(dev)->mite->daq_io_addr + Filter_Interval); + writeb(0x00000000, devpriv->mite->daq_io_addr + Filter_Interval); ret = request_irq(dev->irq, ni_65xx_interrupt, IRQF_SHARED, "ni_65xx", dev); if (ret < 0) { dev->irq = 0; - printk(KERN_WARNING " irq not available"); + dev_warn(dev->class_dev, "irq not available\n"); } - printk("\n"); - return 0; } -static int ni_65xx_detach(struct comedi_device *dev) +static void ni_65xx_detach(struct comedi_device *dev) { - if (private(dev) && private(dev)->mite - && private(dev)->mite->daq_io_addr) { + struct ni_65xx_private *devpriv = dev->private; + + if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr) { writeb(0x00, - private(dev)->mite->daq_io_addr + + devpriv->mite->daq_io_addr + Master_Interrupt_Control); } - if (dev->irq) free_irq(dev->irq, dev); - - if (private(dev)) { - unsigned i; - for (i = 0; i < dev->n_subdevices; ++i) { - kfree(dev->subdevices[i].private); - dev->subdevices[i].private = NULL; + if (devpriv) { + if (devpriv->mite) { + mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); } - if (private(dev)->mite) - mite_unsetup(private(dev)->mite); } - return 0; + comedi_pci_disable(dev); } -static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < n_ni_65xx_boards; i++) { - if (mite_device_id(mite) == ni_65xx_boards[i].dev_id) { - dev->board_ptr = ni_65xx_boards + i; - private(dev)->mite = mite; - return 0; - } - } - } - printk(KERN_WARNING "no device found\n"); - mite_list_devices(); - return -EIO; -} - -static int __devinit driver_ni_65xx_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_ni_65xx.driver_name); -} - -static void __devexit driver_ni_65xx_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_ni_65xx_pci_driver = { - .id_table = ni_65xx_pci_table, - .probe = &driver_ni_65xx_pci_probe, - .remove = __devexit_p(&driver_ni_65xx_pci_remove) +static struct comedi_driver ni_65xx_driver = { + .driver_name = "ni_65xx", + .module = THIS_MODULE, + .auto_attach = ni_65xx_auto_attach, + .detach = ni_65xx_detach, }; -static int __init driver_ni_65xx_init_module(void) +static int ni_65xx_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_ni_65xx); - if (retval < 0) - return retval; - - driver_ni_65xx_pci_driver.name = (char *)driver_ni_65xx.driver_name; - return pci_register_driver(&driver_ni_65xx_pci_driver); + return comedi_pci_auto_config(dev, &ni_65xx_driver, id->driver_data); } -static void __exit driver_ni_65xx_cleanup_module(void) -{ - pci_unregister_driver(&driver_ni_65xx_pci_driver); - comedi_driver_unregister(&driver_ni_65xx); -} +static const struct pci_device_id ni_65xx_pci_table[] = { + { PCI_VDEVICE(NI, 0x1710), BOARD_PXI6509 }, + { PCI_VDEVICE(NI, 0x7085), BOARD_PCI6509 }, + { PCI_VDEVICE(NI, 0x7086), BOARD_PXI6528 }, + { PCI_VDEVICE(NI, 0x7087), BOARD_PCI6515 }, + { PCI_VDEVICE(NI, 0x7088), BOARD_PCI6514 }, + { PCI_VDEVICE(NI, 0x70a9), BOARD_PCI6528 }, + { PCI_VDEVICE(NI, 0x70c3), BOARD_PCI6511 }, + { PCI_VDEVICE(NI, 0x70c8), BOARD_PCI6513 }, + { PCI_VDEVICE(NI, 0x70c9), BOARD_PXI6515 }, + { PCI_VDEVICE(NI, 0x70cc), BOARD_PCI6512 }, + { PCI_VDEVICE(NI, 0x70cd), BOARD_PXI6514 }, + { PCI_VDEVICE(NI, 0x70d1), BOARD_PXI6513 }, + { PCI_VDEVICE(NI, 0x70d2), BOARD_PXI6512 }, + { PCI_VDEVICE(NI, 0x70d3), BOARD_PXI6511 }, + { PCI_VDEVICE(NI, 0x7124), BOARD_PCI6510 }, + { PCI_VDEVICE(NI, 0x7125), BOARD_PCI6516 }, + { PCI_VDEVICE(NI, 0x7126), BOARD_PCI6517 }, + { PCI_VDEVICE(NI, 0x7127), BOARD_PCI6518 }, + { PCI_VDEVICE(NI, 0x7128), BOARD_PCI6519 }, + { PCI_VDEVICE(NI, 0x718b), BOARD_PCI6521 }, + { PCI_VDEVICE(NI, 0x718c), BOARD_PXI6521 }, + { PCI_VDEVICE(NI, 0x71c5), BOARD_PCI6520 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ni_65xx_pci_table); -module_init(driver_ni_65xx_init_module); -module_exit(driver_ni_65xx_cleanup_module); +static struct pci_driver ni_65xx_pci_driver = { + .name = "ni_65xx", + .id_table = ni_65xx_pci_table, + .probe = ni_65xx_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(ni_65xx_driver, ni_65xx_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index 35f3a474982..634cde83a02 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -11,37 +11,36 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* -Driver: ni_660x -Description: National Instruments 660x counter/timer boards -Devices: -[National Instruments] PCI-6601 (ni_660x), PCI-6602, PXI-6602, - PXI-6608 -Author: J.P. Mellor <jpmellor@rose-hulman.edu>, - Herman.Bruyninckx@mech.kuleuven.ac.be, - Wim.Meeussen@mech.kuleuven.ac.be, - Klaas.Gadeyne@mech.kuleuven.ac.be, - Frank Mori Hess <fmhess@users.sourceforge.net> -Updated: Thu Oct 18 12:56:06 EDT 2007 -Status: experimental - -Encoders work. PulseGeneration (both single pulse and pulse train) -works. Buffered commands work for input but not output. - -References: -DAQ 660x Register-Level Programmer Manual (NI 370505A-01) -DAQ 6601/6602 User Manual (NI 322137B-01) - -*/ - + * Driver: ni_660x + * Description: National Instruments 660x counter/timer boards + * Devices: [National Instruments] PCI-6601 (ni_660x), PCI-6602, PXI-6602, + * PXI-6608, PXI-6624 + * Author: J.P. Mellor <jpmellor@rose-hulman.edu>, + * Herman.Bruyninckx@mech.kuleuven.ac.be, + * Wim.Meeussen@mech.kuleuven.ac.be, + * Klaas.Gadeyne@mech.kuleuven.ac.be, + * Frank Mori Hess <fmhess@users.sourceforge.net> + * Updated: Fri, 15 Mar 2013 10:47:56 +0000 + * Status: experimental + * + * Encoders work. PulseGeneration (both single pulse and pulse train) + * works. Buffered commands work for input but not output. + * + * References: + * DAQ 660x Register-Level Programmer Manual (NI 370505A-01) + * DAQ 6601/6602 User Manual (NI 322137B-01) + */ + +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> + #include "../comedidev.h" + +#include "comedi_fc.h" #include "mite.h" #include "ni_tio.h" @@ -57,112 +56,112 @@ for 4 */ #define MAX_DMA_CHANNEL 4 /* See Register-Level Programmer Manual page 3.1 */ -enum NI_660x_Register { - G0InterruptAcknowledge, - G0StatusRegister, - G1InterruptAcknowledge, - G1StatusRegister, - G01StatusRegister, - G0CommandRegister, - STCDIOParallelInput, - G1CommandRegister, - G0HWSaveRegister, - G1HWSaveRegister, - STCDIOOutput, - STCDIOControl, - G0SWSaveRegister, - G1SWSaveRegister, - G0ModeRegister, - G01JointStatus1Register, - G1ModeRegister, - STCDIOSerialInput, - G0LoadARegister, - G01JointStatus2Register, - G0LoadBRegister, - G1LoadARegister, - G1LoadBRegister, - G0InputSelectRegister, - G1InputSelectRegister, - G0AutoincrementRegister, - G1AutoincrementRegister, - G01JointResetRegister, - G0InterruptEnable, - G1InterruptEnable, - G0CountingModeRegister, - G1CountingModeRegister, - G0SecondGateRegister, - G1SecondGateRegister, - G0DMAConfigRegister, - G0DMAStatusRegister, - G1DMAConfigRegister, - G1DMAStatusRegister, - G2InterruptAcknowledge, - G2StatusRegister, - G3InterruptAcknowledge, - G3StatusRegister, - G23StatusRegister, - G2CommandRegister, - G3CommandRegister, - G2HWSaveRegister, - G3HWSaveRegister, - G2SWSaveRegister, - G3SWSaveRegister, - G2ModeRegister, - G23JointStatus1Register, - G3ModeRegister, - G2LoadARegister, - G23JointStatus2Register, - G2LoadBRegister, - G3LoadARegister, - G3LoadBRegister, - G2InputSelectRegister, - G3InputSelectRegister, - G2AutoincrementRegister, - G3AutoincrementRegister, - G23JointResetRegister, - G2InterruptEnable, - G3InterruptEnable, - G2CountingModeRegister, - G3CountingModeRegister, - G3SecondGateRegister, - G2SecondGateRegister, - G2DMAConfigRegister, - G2DMAStatusRegister, - G3DMAConfigRegister, - G3DMAStatusRegister, - DIO32Input, - DIO32Output, - ClockConfigRegister, - GlobalInterruptStatusRegister, - DMAConfigRegister, - GlobalInterruptConfigRegister, - IOConfigReg0_1, - IOConfigReg2_3, - IOConfigReg4_5, - IOConfigReg6_7, - IOConfigReg8_9, - IOConfigReg10_11, - IOConfigReg12_13, - IOConfigReg14_15, - IOConfigReg16_17, - IOConfigReg18_19, - IOConfigReg20_21, - IOConfigReg22_23, - IOConfigReg24_25, - IOConfigReg26_27, - IOConfigReg28_29, - IOConfigReg30_31, - IOConfigReg32_33, - IOConfigReg34_35, - IOConfigReg36_37, - IOConfigReg38_39, - NumRegisters, +enum ni_660x_register { + NI660X_G0_INT_ACK, + NI660X_G0_STATUS, + NI660X_G1_INT_ACK, + NI660X_G1_STATUS, + NI660X_G01_STATUS, + NI660X_G0_CMD, + NI660X_STC_DIO_PARALLEL_INPUT, + NI660X_G1_CMD, + NI660X_G0_HW_SAVE, + NI660X_G1_HW_SAVE, + NI660X_STC_DIO_OUTPUT, + NI660X_STC_DIO_CONTROL, + NI660X_G0_SW_SAVE, + NI660X_G1_SW_SAVE, + NI660X_G0_MODE, + NI660X_G01_STATUS1, + NI660X_G1_MODE, + NI660X_STC_DIO_SERIAL_INPUT, + NI660X_G0_LOADA, + NI660X_G01_STATUS2, + NI660X_G0_LOADB, + NI660X_G1_LOADA, + NI660X_G1_LOADB, + NI660X_G0_INPUT_SEL, + NI660X_G1_INPUT_SEL, + NI660X_G0_AUTO_INC, + NI660X_G1_AUTO_INC, + NI660X_G01_RESET, + NI660X_G0_INT_ENA, + NI660X_G1_INT_ENA, + NI660X_G0_CNT_MODE, + NI660X_G1_CNT_MODE, + NI660X_G0_GATE2, + NI660X_G1_GATE2, + NI660X_G0_DMA_CFG, + NI660X_G0_DMA_STATUS, + NI660X_G1_DMA_CFG, + NI660X_G1_DMA_STATUS, + NI660X_G2_INT_ACK, + NI660X_G2_STATUS, + NI660X_G3_INT_ACK, + NI660X_G3_STATUS, + NI660X_G23_STATUS, + NI660X_G2_CMD, + NI660X_G3_CMD, + NI660X_G2_HW_SAVE, + NI660X_G3_HW_SAVE, + NI660X_G2_SW_SAVE, + NI660X_G3_SW_SAVE, + NI660X_G2_MODE, + NI660X_G23_STATUS1, + NI660X_G3_MODE, + NI660X_G2_LOADA, + NI660X_G23_STATUS2, + NI660X_G2_LOADB, + NI660X_G3_LOADA, + NI660X_G3_LOADB, + NI660X_G2_INPUT_SEL, + NI660X_G3_INPUT_SEL, + NI660X_G2_AUTO_INC, + NI660X_G3_AUTO_INC, + NI660X_G23_RESET, + NI660X_G2_INT_ENA, + NI660X_G3_INT_ENA, + NI660X_G2_CNT_MODE, + NI660X_G3_CNT_MODE, + NI660X_G3_GATE2, + NI660X_G2_GATE2, + NI660X_G2_DMA_CFG, + NI660X_G2_DMA_STATUS, + NI660X_G3_DMA_CFG, + NI660X_G3_DMA_STATUS, + NI660X_DIO32_INPUT, + NI660X_DIO32_OUTPUT, + NI660X_CLK_CFG, + NI660X_GLOBAL_INT_STATUS, + NI660X_DMA_CFG, + NI660X_GLOBAL_INT_CFG, + NI660X_IO_CFG_0_1, + NI660X_IO_CFG_2_3, + NI660X_IO_CFG_4_5, + NI660X_IO_CFG_6_7, + NI660X_IO_CFG_8_9, + NI660X_IO_CFG_10_11, + NI660X_IO_CFG_12_13, + NI660X_IO_CFG_14_15, + NI660X_IO_CFG_16_17, + NI660X_IO_CFG_18_19, + NI660X_IO_CFG_20_21, + NI660X_IO_CFG_22_23, + NI660X_IO_CFG_24_25, + NI660X_IO_CFG_26_27, + NI660X_IO_CFG_28_29, + NI660X_IO_CFG_30_31, + NI660X_IO_CFG_32_33, + NI660X_IO_CFG_34_35, + NI660X_IO_CFG_36_37, + NI660X_IO_CFG_38_39, + NI660X_NUM_REGS, }; static inline unsigned IOConfigReg(unsigned pfi_channel) { - unsigned reg = IOConfigReg0_1 + pfi_channel / 2; - BUG_ON(reg > IOConfigReg38_39); + unsigned reg = NI660X_IO_CFG_0_1 + pfi_channel / 2; + BUG_ON(reg > NI660X_IO_CFG_38_39); return reg; } @@ -202,7 +201,7 @@ struct NI_660xRegisterData { enum ni_660x_register_width size; /* 1 byte, 2 bytes, or 4 bytes */ }; -static const struct NI_660xRegisterData registerData[NumRegisters] = { +static const struct NI_660xRegisterData registerData[NI660X_NUM_REGS] = { {"G0 Interrupt Acknowledge", 0x004, NI_660x_WRITE, DATA_2B}, {"G0 Status Register", 0x004, NI_660x_READ, DATA_2B}, {"G1 Interrupt Acknowledge", 0x006, NI_660x_WRITE, DATA_2B}, @@ -349,11 +348,6 @@ static inline unsigned dma_select_mask(unsigned dma_channel) enum dma_selection { dma_selection_none = 0x1f, }; -static inline unsigned dma_selection_counter(unsigned counter_index) -{ - BUG_ON(counter_index >= counters_per_chip); - return counter_index; -} static inline unsigned dma_select_bits(unsigned dma_channel, unsigned selection) { @@ -386,49 +380,45 @@ enum global_interrupt_config_register_bits { /* First chip is at base-address + 0x00, etc. */ static const unsigned GPCT_OFFSET[2] = { 0x0, 0x800 }; -/* Board description*/ +enum ni_660x_boardid { + BOARD_PCI6601, + BOARD_PCI6602, + BOARD_PXI6602, + BOARD_PXI6608, + BOARD_PXI6624 +}; + struct ni_660x_board { - unsigned short dev_id; /* `lspci` will show you this */ const char *name; unsigned n_chips; /* total number of TIO chips */ }; static const struct ni_660x_board ni_660x_boards[] = { - { - .dev_id = 0x2c60, - .name = "PCI-6601", - .n_chips = 1, - }, - { - .dev_id = 0x1310, - .name = "PCI-6602", - .n_chips = 2, - }, - { - .dev_id = 0x1360, - .name = "PXI-6602", - .n_chips = 2, - }, - { - .dev_id = 0x2cc0, - .name = "PXI-6608", - .n_chips = 2, - }, + [BOARD_PCI6601] = { + .name = "PCI-6601", + .n_chips = 1, + }, + [BOARD_PCI6602] = { + .name = "PCI-6602", + .n_chips = 2, + }, + [BOARD_PXI6602] = { + .name = "PXI-6602", + .n_chips = 2, + }, + [BOARD_PXI6608] = { + .name = "PXI-6608", + .n_chips = 2, + }, + [BOARD_PXI6624] = { + .name = "PXI-6624", + .n_chips = 2, + }, }; #define NI_660X_MAX_NUM_CHIPS 2 #define NI_660X_MAX_NUM_COUNTERS (NI_660X_MAX_NUM_CHIPS * counters_per_chip) -static DEFINE_PCI_DEVICE_TABLE(ni_660x_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c60)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1310)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1360)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2cc0)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, ni_660x_pci_table); - struct ni_660x_private { struct mite_struct *mite; struct ni_gpct_device *counter_dev; @@ -443,326 +433,165 @@ struct ni_660x_private { unsigned short pfi_output_selects[NUM_PFI_CHANNELS]; }; -static inline struct ni_660x_private *private(struct comedi_device *dev) -{ - return dev->private; -} - -/* initialized in ni_660x_find_device() */ -static inline const struct ni_660x_board *board(struct comedi_device *dev) -{ - return dev->board_ptr; -} - -#define n_ni_660x_boards ARRAY_SIZE(ni_660x_boards) - -static int ni_660x_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int ni_660x_detach(struct comedi_device *dev); -static void init_tio_chip(struct comedi_device *dev, int chipset); -static void ni_660x_select_pfi_output(struct comedi_device *dev, - unsigned pfi_channel, - unsigned output_select); - -static struct comedi_driver driver_ni_660x = { - .driver_name = "ni_660x", - .module = THIS_MODULE, - .attach = ni_660x_attach, - .detach = ni_660x_detach, -}; - -static int __devinit driver_ni_660x_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_ni_660x.driver_name); -} - -static void __devexit driver_ni_660x_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_ni_660x_pci_driver = { - .id_table = ni_660x_pci_table, - .probe = &driver_ni_660x_pci_probe, - .remove = __devexit_p(&driver_ni_660x_pci_remove) -}; - -static int __init driver_ni_660x_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_ni_660x); - if (retval < 0) - return retval; - - driver_ni_660x_pci_driver.name = (char *)driver_ni_660x.driver_name; - return pci_register_driver(&driver_ni_660x_pci_driver); -} - -static void __exit driver_ni_660x_cleanup_module(void) -{ - pci_unregister_driver(&driver_ni_660x_pci_driver); - comedi_driver_unregister(&driver_ni_660x); -} - -module_init(driver_ni_660x_init_module); -module_exit(driver_ni_660x_cleanup_module); - -static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot); -static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan, - unsigned source); - -/* Possible instructions for a GPCT */ -static int ni_660x_GPCT_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ni_660x_GPCT_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int ni_660x_GPCT_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* Possible instructions for Digital IO */ -static int ni_660x_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static int ni_660x_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - static inline unsigned ni_660x_num_counters(struct comedi_device *dev) { - return board(dev)->n_chips * counters_per_chip; + const struct ni_660x_board *board = comedi_board(dev); + + return board->n_chips * counters_per_chip; } -static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg) +static enum ni_660x_register ni_gpct_to_660x_register(enum ni_gpct_register reg) { - enum NI_660x_Register ni_660x_register; switch (reg) { - case NITIO_G0_Autoincrement_Reg: - ni_660x_register = G0AutoincrementRegister; - break; - case NITIO_G1_Autoincrement_Reg: - ni_660x_register = G1AutoincrementRegister; - break; - case NITIO_G2_Autoincrement_Reg: - ni_660x_register = G2AutoincrementRegister; - break; - case NITIO_G3_Autoincrement_Reg: - ni_660x_register = G3AutoincrementRegister; - break; - case NITIO_G0_Command_Reg: - ni_660x_register = G0CommandRegister; - break; - case NITIO_G1_Command_Reg: - ni_660x_register = G1CommandRegister; - break; - case NITIO_G2_Command_Reg: - ni_660x_register = G2CommandRegister; - break; - case NITIO_G3_Command_Reg: - ni_660x_register = G3CommandRegister; - break; - case NITIO_G0_HW_Save_Reg: - ni_660x_register = G0HWSaveRegister; - break; - case NITIO_G1_HW_Save_Reg: - ni_660x_register = G1HWSaveRegister; - break; - case NITIO_G2_HW_Save_Reg: - ni_660x_register = G2HWSaveRegister; - break; - case NITIO_G3_HW_Save_Reg: - ni_660x_register = G3HWSaveRegister; - break; - case NITIO_G0_SW_Save_Reg: - ni_660x_register = G0SWSaveRegister; - break; - case NITIO_G1_SW_Save_Reg: - ni_660x_register = G1SWSaveRegister; - break; - case NITIO_G2_SW_Save_Reg: - ni_660x_register = G2SWSaveRegister; - break; - case NITIO_G3_SW_Save_Reg: - ni_660x_register = G3SWSaveRegister; - break; - case NITIO_G0_Mode_Reg: - ni_660x_register = G0ModeRegister; - break; - case NITIO_G1_Mode_Reg: - ni_660x_register = G1ModeRegister; - break; - case NITIO_G2_Mode_Reg: - ni_660x_register = G2ModeRegister; - break; - case NITIO_G3_Mode_Reg: - ni_660x_register = G3ModeRegister; - break; - case NITIO_G0_LoadA_Reg: - ni_660x_register = G0LoadARegister; - break; - case NITIO_G1_LoadA_Reg: - ni_660x_register = G1LoadARegister; - break; - case NITIO_G2_LoadA_Reg: - ni_660x_register = G2LoadARegister; - break; - case NITIO_G3_LoadA_Reg: - ni_660x_register = G3LoadARegister; - break; - case NITIO_G0_LoadB_Reg: - ni_660x_register = G0LoadBRegister; - break; - case NITIO_G1_LoadB_Reg: - ni_660x_register = G1LoadBRegister; - break; - case NITIO_G2_LoadB_Reg: - ni_660x_register = G2LoadBRegister; - break; - case NITIO_G3_LoadB_Reg: - ni_660x_register = G3LoadBRegister; - break; - case NITIO_G0_Input_Select_Reg: - ni_660x_register = G0InputSelectRegister; - break; - case NITIO_G1_Input_Select_Reg: - ni_660x_register = G1InputSelectRegister; - break; - case NITIO_G2_Input_Select_Reg: - ni_660x_register = G2InputSelectRegister; - break; - case NITIO_G3_Input_Select_Reg: - ni_660x_register = G3InputSelectRegister; - break; - case NITIO_G01_Status_Reg: - ni_660x_register = G01StatusRegister; - break; - case NITIO_G23_Status_Reg: - ni_660x_register = G23StatusRegister; - break; - case NITIO_G01_Joint_Reset_Reg: - ni_660x_register = G01JointResetRegister; - break; - case NITIO_G23_Joint_Reset_Reg: - ni_660x_register = G23JointResetRegister; - break; - case NITIO_G01_Joint_Status1_Reg: - ni_660x_register = G01JointStatus1Register; - break; - case NITIO_G23_Joint_Status1_Reg: - ni_660x_register = G23JointStatus1Register; - break; - case NITIO_G01_Joint_Status2_Reg: - ni_660x_register = G01JointStatus2Register; - break; - case NITIO_G23_Joint_Status2_Reg: - ni_660x_register = G23JointStatus2Register; - break; - case NITIO_G0_Counting_Mode_Reg: - ni_660x_register = G0CountingModeRegister; - break; - case NITIO_G1_Counting_Mode_Reg: - ni_660x_register = G1CountingModeRegister; - break; - case NITIO_G2_Counting_Mode_Reg: - ni_660x_register = G2CountingModeRegister; - break; - case NITIO_G3_Counting_Mode_Reg: - ni_660x_register = G3CountingModeRegister; - break; - case NITIO_G0_Second_Gate_Reg: - ni_660x_register = G0SecondGateRegister; - break; - case NITIO_G1_Second_Gate_Reg: - ni_660x_register = G1SecondGateRegister; - break; - case NITIO_G2_Second_Gate_Reg: - ni_660x_register = G2SecondGateRegister; - break; - case NITIO_G3_Second_Gate_Reg: - ni_660x_register = G3SecondGateRegister; - break; - case NITIO_G0_DMA_Config_Reg: - ni_660x_register = G0DMAConfigRegister; - break; - case NITIO_G0_DMA_Status_Reg: - ni_660x_register = G0DMAStatusRegister; - break; - case NITIO_G1_DMA_Config_Reg: - ni_660x_register = G1DMAConfigRegister; - break; - case NITIO_G1_DMA_Status_Reg: - ni_660x_register = G1DMAStatusRegister; - break; - case NITIO_G2_DMA_Config_Reg: - ni_660x_register = G2DMAConfigRegister; - break; - case NITIO_G2_DMA_Status_Reg: - ni_660x_register = G2DMAStatusRegister; - break; - case NITIO_G3_DMA_Config_Reg: - ni_660x_register = G3DMAConfigRegister; - break; - case NITIO_G3_DMA_Status_Reg: - ni_660x_register = G3DMAStatusRegister; - break; - case NITIO_G0_Interrupt_Acknowledge_Reg: - ni_660x_register = G0InterruptAcknowledge; - break; - case NITIO_G1_Interrupt_Acknowledge_Reg: - ni_660x_register = G1InterruptAcknowledge; - break; - case NITIO_G2_Interrupt_Acknowledge_Reg: - ni_660x_register = G2InterruptAcknowledge; - break; - case NITIO_G3_Interrupt_Acknowledge_Reg: - ni_660x_register = G3InterruptAcknowledge; - break; - case NITIO_G0_Status_Reg: - ni_660x_register = G0StatusRegister; - break; - case NITIO_G1_Status_Reg: - ni_660x_register = G1StatusRegister; - break; - case NITIO_G2_Status_Reg: - ni_660x_register = G2StatusRegister; - break; - case NITIO_G3_Status_Reg: - ni_660x_register = G3StatusRegister; - break; - case NITIO_G0_Interrupt_Enable_Reg: - ni_660x_register = G0InterruptEnable; - break; - case NITIO_G1_Interrupt_Enable_Reg: - ni_660x_register = G1InterruptEnable; - break; - case NITIO_G2_Interrupt_Enable_Reg: - ni_660x_register = G2InterruptEnable; - break; - case NITIO_G3_Interrupt_Enable_Reg: - ni_660x_register = G3InterruptEnable; - break; + case NITIO_G0_AUTO_INC: + return NI660X_G0_AUTO_INC; + case NITIO_G1_AUTO_INC: + return NI660X_G1_AUTO_INC; + case NITIO_G2_AUTO_INC: + return NI660X_G2_AUTO_INC; + case NITIO_G3_AUTO_INC: + return NI660X_G3_AUTO_INC; + case NITIO_G0_CMD: + return NI660X_G0_CMD; + case NITIO_G1_CMD: + return NI660X_G1_CMD; + case NITIO_G2_CMD: + return NI660X_G2_CMD; + case NITIO_G3_CMD: + return NI660X_G3_CMD; + case NITIO_G0_HW_SAVE: + return NI660X_G0_HW_SAVE; + case NITIO_G1_HW_SAVE: + return NI660X_G1_HW_SAVE; + case NITIO_G2_HW_SAVE: + return NI660X_G2_HW_SAVE; + case NITIO_G3_HW_SAVE: + return NI660X_G3_HW_SAVE; + case NITIO_G0_SW_SAVE: + return NI660X_G0_SW_SAVE; + case NITIO_G1_SW_SAVE: + return NI660X_G1_SW_SAVE; + case NITIO_G2_SW_SAVE: + return NI660X_G2_SW_SAVE; + case NITIO_G3_SW_SAVE: + return NI660X_G3_SW_SAVE; + case NITIO_G0_MODE: + return NI660X_G0_MODE; + case NITIO_G1_MODE: + return NI660X_G1_MODE; + case NITIO_G2_MODE: + return NI660X_G2_MODE; + case NITIO_G3_MODE: + return NI660X_G3_MODE; + case NITIO_G0_LOADA: + return NI660X_G0_LOADA; + case NITIO_G1_LOADA: + return NI660X_G1_LOADA; + case NITIO_G2_LOADA: + return NI660X_G2_LOADA; + case NITIO_G3_LOADA: + return NI660X_G3_LOADA; + case NITIO_G0_LOADB: + return NI660X_G0_LOADB; + case NITIO_G1_LOADB: + return NI660X_G1_LOADB; + case NITIO_G2_LOADB: + return NI660X_G2_LOADB; + case NITIO_G3_LOADB: + return NI660X_G3_LOADB; + case NITIO_G0_INPUT_SEL: + return NI660X_G0_INPUT_SEL; + case NITIO_G1_INPUT_SEL: + return NI660X_G1_INPUT_SEL; + case NITIO_G2_INPUT_SEL: + return NI660X_G2_INPUT_SEL; + case NITIO_G3_INPUT_SEL: + return NI660X_G3_INPUT_SEL; + case NITIO_G01_STATUS: + return NI660X_G01_STATUS; + case NITIO_G23_STATUS: + return NI660X_G23_STATUS; + case NITIO_G01_RESET: + return NI660X_G01_RESET; + case NITIO_G23_RESET: + return NI660X_G23_RESET; + case NITIO_G01_STATUS1: + return NI660X_G01_STATUS1; + case NITIO_G23_STATUS1: + return NI660X_G23_STATUS1; + case NITIO_G01_STATUS2: + return NI660X_G01_STATUS2; + case NITIO_G23_STATUS2: + return NI660X_G23_STATUS2; + case NITIO_G0_CNT_MODE: + return NI660X_G0_CNT_MODE; + case NITIO_G1_CNT_MODE: + return NI660X_G1_CNT_MODE; + case NITIO_G2_CNT_MODE: + return NI660X_G2_CNT_MODE; + case NITIO_G3_CNT_MODE: + return NI660X_G3_CNT_MODE; + case NITIO_G0_GATE2: + return NI660X_G0_GATE2; + case NITIO_G1_GATE2: + return NI660X_G1_GATE2; + case NITIO_G2_GATE2: + return NI660X_G2_GATE2; + case NITIO_G3_GATE2: + return NI660X_G3_GATE2; + case NITIO_G0_DMA_CFG: + return NI660X_G0_DMA_CFG; + case NITIO_G0_DMA_STATUS: + return NI660X_G0_DMA_STATUS; + case NITIO_G1_DMA_CFG: + return NI660X_G1_DMA_CFG; + case NITIO_G1_DMA_STATUS: + return NI660X_G1_DMA_STATUS; + case NITIO_G2_DMA_CFG: + return NI660X_G2_DMA_CFG; + case NITIO_G2_DMA_STATUS: + return NI660X_G2_DMA_STATUS; + case NITIO_G3_DMA_CFG: + return NI660X_G3_DMA_CFG; + case NITIO_G3_DMA_STATUS: + return NI660X_G3_DMA_STATUS; + case NITIO_G0_INT_ACK: + return NI660X_G0_INT_ACK; + case NITIO_G1_INT_ACK: + return NI660X_G1_INT_ACK; + case NITIO_G2_INT_ACK: + return NI660X_G2_INT_ACK; + case NITIO_G3_INT_ACK: + return NI660X_G3_INT_ACK; + case NITIO_G0_STATUS: + return NI660X_G0_STATUS; + case NITIO_G1_STATUS: + return NI660X_G1_STATUS; + case NITIO_G2_STATUS: + return NI660X_G2_STATUS; + case NITIO_G3_STATUS: + return NI660X_G3_STATUS; + case NITIO_G0_INT_ENA: + return NI660X_G0_INT_ENA; + case NITIO_G1_INT_ENA: + return NI660X_G1_INT_ENA; + case NITIO_G2_INT_ENA: + return NI660X_G2_INT_ENA; + case NITIO_G3_INT_ENA: + return NI660X_G3_INT_ENA; default: - printk(KERN_WARNING "%s: unhandled register 0x%x in switch.\n", - __func__, reg); BUG(); return 0; - break; } - return ni_660x_register; } static inline void ni_660x_write_register(struct comedi_device *dev, - unsigned chip_index, unsigned bits, - enum NI_660x_Register reg) + unsigned chip, unsigned bits, + enum ni_660x_register reg) { - void *const write_address = - private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] + + struct ni_660x_private *devpriv = dev->private; + void __iomem *write_address = + devpriv->mite->daq_io_addr + GPCT_OFFSET[chip] + registerData[reg].offset; switch (registerData[reg].size) { @@ -773,19 +602,18 @@ static inline void ni_660x_write_register(struct comedi_device *dev, writel(bits, write_address); break; default: - printk(KERN_WARNING "%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", - __FILE__, __func__, reg); BUG(); break; } } static inline unsigned ni_660x_read_register(struct comedi_device *dev, - unsigned chip_index, - enum NI_660x_Register reg) + unsigned chip, + enum ni_660x_register reg) { - void *const read_address = - private(dev)->mite->daq_io_addr + GPCT_OFFSET[chip_index] + + struct ni_660x_private *devpriv = dev->private; + void __iomem *read_address = + devpriv->mite->daq_io_addr + GPCT_OFFSET[chip] + registerData[reg].offset; switch (registerData[reg].size) { @@ -796,8 +624,6 @@ static inline unsigned ni_660x_read_register(struct comedi_device *dev, return readl(read_address); break; default: - printk(KERN_WARNING "%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", - __FILE__, __func__, reg); BUG(); break; } @@ -808,18 +634,20 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg) { struct comedi_device *dev = counter->counter_dev->dev; - enum NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg); - ni_660x_write_register(dev, counter->chip_index, bits, - ni_660x_register); + enum ni_660x_register ni_660x_register = ni_gpct_to_660x_register(reg); + unsigned chip = counter->chip_index; + + ni_660x_write_register(dev, chip, bits, ni_660x_register); } static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg) { struct comedi_device *dev = counter->counter_dev->dev; - enum NI_660x_Register ni_660x_register = ni_gpct_to_660x_register(reg); - return ni_660x_read_register(dev, counter->chip_index, - ni_660x_register); + enum ni_660x_register ni_660x_register = ni_gpct_to_660x_register(reg); + unsigned chip = counter->chip_index; + + return ni_660x_read_register(dev, chip, ni_660x_register); } static inline struct mite_dma_descriptor_ring *mite_ring(struct ni_660x_private @@ -827,61 +655,65 @@ static inline struct mite_dma_descriptor_ring *mite_ring(struct ni_660x_private struct ni_gpct *counter) { - return priv->mite_rings[counter->chip_index][counter->counter_index]; + unsigned chip = counter->chip_index; + + return priv->mite_rings[chip][counter->counter_index]; } static inline void ni_660x_set_dma_channel(struct comedi_device *dev, unsigned mite_channel, struct ni_gpct *counter) { + struct ni_660x_private *devpriv = dev->private; + unsigned chip = counter->chip_index; unsigned long flags; - spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags); - private(dev)->dma_configuration_soft_copies[counter->chip_index] &= - ~dma_select_mask(mite_channel); - private(dev)->dma_configuration_soft_copies[counter->chip_index] |= - dma_select_bits(mite_channel, - dma_selection_counter(counter->counter_index)); - ni_660x_write_register(dev, counter->chip_index, - private(dev)-> - dma_configuration_soft_copies - [counter->chip_index] | - dma_reset_bit(mite_channel), DMAConfigRegister); + + spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); + devpriv->dma_configuration_soft_copies[chip] &= + ~dma_select_mask(mite_channel); + devpriv->dma_configuration_soft_copies[chip] |= + dma_select_bits(mite_channel, counter->counter_index); + ni_660x_write_register(dev, chip, + devpriv->dma_configuration_soft_copies[chip] | + dma_reset_bit(mite_channel), NI660X_DMA_CFG); mmiowb(); - spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags); + spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); } static inline void ni_660x_unset_dma_channel(struct comedi_device *dev, unsigned mite_channel, struct ni_gpct *counter) { + struct ni_660x_private *devpriv = dev->private; + unsigned chip = counter->chip_index; unsigned long flags; - spin_lock_irqsave(&private(dev)->soft_reg_copy_lock, flags); - private(dev)->dma_configuration_soft_copies[counter->chip_index] &= + + spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); + devpriv->dma_configuration_soft_copies[chip] &= ~dma_select_mask(mite_channel); - private(dev)->dma_configuration_soft_copies[counter->chip_index] |= + devpriv->dma_configuration_soft_copies[chip] |= dma_select_bits(mite_channel, dma_selection_none); - ni_660x_write_register(dev, counter->chip_index, - private(dev)-> - dma_configuration_soft_copies - [counter->chip_index], DMAConfigRegister); + ni_660x_write_register(dev, chip, + devpriv->dma_configuration_soft_copies[chip], + NI660X_DMA_CFG); mmiowb(); - spin_unlock_irqrestore(&private(dev)->soft_reg_copy_lock, flags); + spin_unlock_irqrestore(&devpriv->soft_reg_copy_lock, flags); } static int ni_660x_request_mite_channel(struct comedi_device *dev, struct ni_gpct *counter, enum comedi_io_direction direction) { + struct ni_660x_private *devpriv = dev->private; unsigned long flags; struct mite_channel *mite_chan; - spin_lock_irqsave(&private(dev)->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); BUG_ON(counter->mite_chan); - mite_chan = - mite_request_channel(private(dev)->mite, mite_ring(private(dev), - counter)); + mite_chan = mite_request_channel(devpriv->mite, + mite_ring(devpriv, counter)); if (mite_chan == NULL) { - spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); comedi_error(dev, "failed to reserve mite dma channel for counter."); return -EBUSY; @@ -889,16 +721,17 @@ static int ni_660x_request_mite_channel(struct comedi_device *dev, mite_chan->dir = direction; ni_tio_set_mite_channel(counter, mite_chan); ni_660x_set_dma_channel(dev, mite_chan->channel, counter); - spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); return 0; } -void ni_660x_release_mite_channel(struct comedi_device *dev, - struct ni_gpct *counter) +static void ni_660x_release_mite_channel(struct comedi_device *dev, + struct ni_gpct *counter) { + struct ni_660x_private *devpriv = dev->private; unsigned long flags; - spin_lock_irqsave(&private(dev)->mite_channel_lock, flags); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (counter->mite_chan) { struct mite_channel *mite_chan = counter->mite_chan; @@ -906,16 +739,14 @@ void ni_660x_release_mite_channel(struct comedi_device *dev, ni_tio_set_mite_channel(counter, NULL); mite_release_channel(mite_chan); } - spin_unlock_irqrestore(&private(dev)->mite_channel_lock, flags); + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct ni_gpct *counter = s->private; int retval; - struct ni_gpct *counter = subdev_to_counter(s); -/* const struct comedi_cmd *cmd = &s->async->cmd; */ - retval = ni_660x_request_mite_channel(dev, counter, COMEDI_INPUT); if (retval) { comedi_error(dev, @@ -923,22 +754,13 @@ static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return retval; } ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL); - retval = ni_tio_cmd(counter, s->async); - return retval; -} - -static int ni_660x_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - struct ni_gpct *counter = subdev_to_counter(s); - - return ni_tio_cmdtest(counter, cmd); + return ni_tio_cmd(dev, s); } static int ni_660x_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct ni_gpct *counter = subdev_to_counter(s); + struct ni_gpct *counter = s->private; int retval; retval = ni_tio_cancel(counter); @@ -946,71 +768,75 @@ static int ni_660x_cancel(struct comedi_device *dev, struct comedi_subdevice *s) return retval; } -static void set_tio_counterswap(struct comedi_device *dev, int chipset) +static void set_tio_counterswap(struct comedi_device *dev, int chip) { - /* See P. 3.5 of the Register-Level Programming manual. The - CounterSwap bit has to be set on the second chip, otherwise - it will try to use the same pins as the first chip. + unsigned bits = 0; + + /* + * See P. 3.5 of the Register-Level Programming manual. + * The CounterSwap bit has to be set on the second chip, + * otherwise it will try to use the same pins as the + * first chip. */ - if (chipset) - ni_660x_write_register(dev, chipset, CounterSwap, - ClockConfigRegister); - else - ni_660x_write_register(dev, chipset, 0, ClockConfigRegister); + if (chip) + bits = CounterSwap; + + ni_660x_write_register(dev, chip, bits, NI660X_CLK_CFG); } static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) { - ni_tio_handle_interrupt(subdev_to_counter(s), s); - if (s->async->events) { - if (s->async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_660x_cancel(dev, s); - } - comedi_event(dev, s); - } + struct ni_gpct *counter = s->private; + + ni_tio_handle_interrupt(counter, s); + cfc_handle_events(dev, s); } static irqreturn_t ni_660x_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct ni_660x_private *devpriv = dev->private; struct comedi_subdevice *s; unsigned i; unsigned long flags; - if (dev->attached == 0) + if (!dev->attached) return IRQ_NONE; /* lock to avoid race with comedi_poll */ - spin_lock_irqsave(&private(dev)->interrupt_lock, flags); + spin_lock_irqsave(&devpriv->interrupt_lock, flags); smp_mb(); for (i = 0; i < ni_660x_num_counters(dev); ++i) { - s = dev->subdevices + NI_660X_GPCT_SUBDEV(i); + s = &dev->subdevices[NI_660X_GPCT_SUBDEV(i)]; ni_660x_handle_gpct_interrupt(dev, s); } - spin_unlock_irqrestore(&private(dev)->interrupt_lock, flags); + spin_unlock_irqrestore(&devpriv->interrupt_lock, flags); return IRQ_HANDLED; } static int ni_660x_input_poll(struct comedi_device *dev, struct comedi_subdevice *s) { + struct ni_660x_private *devpriv = dev->private; + struct ni_gpct *counter = s->private; unsigned long flags; + /* lock to avoid race with comedi_poll */ - spin_lock_irqsave(&private(dev)->interrupt_lock, flags); - mite_sync_input_dma(subdev_to_counter(s)->mite_chan, s->async); - spin_unlock_irqrestore(&private(dev)->interrupt_lock, flags); - return comedi_buf_read_n_available(s->async); + spin_lock_irqsave(&devpriv->interrupt_lock, flags); + mite_sync_input_dma(counter->mite_chan, s); + spin_unlock_irqrestore(&devpriv->interrupt_lock, flags); + return comedi_buf_read_n_available(s); } static int ni_660x_buf_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { + struct ni_660x_private *devpriv = dev->private; + struct ni_gpct *counter = s->private; int ret; - ret = mite_buf_change(mite_ring(private(dev), subdev_to_counter(s)), - s->async); + ret = mite_buf_change(mite_ring(devpriv, counter), s); if (ret < 0) return ret; @@ -1019,32 +845,34 @@ static int ni_660x_buf_change(struct comedi_device *dev, static int ni_660x_allocate_private(struct comedi_device *dev) { - int retval; + struct ni_660x_private *devpriv; unsigned i; - retval = alloc_private(dev, sizeof(struct ni_660x_private)); - if (retval < 0) - return retval; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - spin_lock_init(&private(dev)->mite_channel_lock); - spin_lock_init(&private(dev)->interrupt_lock); - spin_lock_init(&private(dev)->soft_reg_copy_lock); + spin_lock_init(&devpriv->mite_channel_lock); + spin_lock_init(&devpriv->interrupt_lock); + spin_lock_init(&devpriv->soft_reg_copy_lock); for (i = 0; i < NUM_PFI_CHANNELS; ++i) - private(dev)->pfi_output_selects[i] = pfi_output_select_counter; + devpriv->pfi_output_selects[i] = pfi_output_select_counter; return 0; } static int ni_660x_alloc_mite_rings(struct comedi_device *dev) { + const struct ni_660x_board *board = comedi_board(dev); + struct ni_660x_private *devpriv = dev->private; unsigned i; unsigned j; - for (i = 0; i < board(dev)->n_chips; ++i) { + for (i = 0; i < board->n_chips; ++i) { for (j = 0; j < counters_per_chip; ++j) { - private(dev)->mite_rings[i][j] = - mite_alloc_ring(private(dev)->mite); - if (private(dev)->mite_rings[i][j] == NULL) + devpriv->mite_rings[i][j] = + mite_alloc_ring(devpriv->mite); + if (devpriv->mite_rings[i][j] == NULL) return -ENOMEM; } } @@ -1053,226 +881,35 @@ 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); + struct ni_660x_private *devpriv = dev->private; unsigned i; unsigned j; - for (i = 0; i < board(dev)->n_chips; ++i) { + for (i = 0; i < board->n_chips; ++i) { for (j = 0; j < counters_per_chip; ++j) - mite_free_ring(private(dev)->mite_rings[i][j]); + mite_free_ring(devpriv->mite_rings[i][j]); } } -static int ni_660x_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int ret; - unsigned i; - unsigned global_interrupt_config_bits; - - printk(KERN_INFO "comedi%d: ni_660x: ", dev->minor); - - ret = ni_660x_allocate_private(dev); - if (ret < 0) - return ret; - ret = ni_660x_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; - - dev->board_name = board(dev)->name; - - ret = mite_setup2(private(dev)->mite, 1); - if (ret < 0) { - printk(KERN_WARNING "error setting up mite\n"); - return ret; - } - comedi_set_hw_dev(dev, &private(dev)->mite->pcidev->dev); - ret = ni_660x_alloc_mite_rings(dev); - if (ret < 0) - return ret; - - printk(KERN_INFO " %s ", dev->board_name); - - dev->n_subdevices = 2 + NI_660X_MAX_NUM_COUNTERS; - - if (alloc_subdevices(dev, dev->n_subdevices) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* Old GENERAL-PURPOSE COUNTER/TIME (GPCT) subdevice, no longer used */ - s->type = COMEDI_SUBD_UNUSED; - - s = dev->subdevices + NI_660X_DIO_SUBDEV; - /* DIGITAL I/O SUBDEVICE */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = NUM_PFI_CHANNELS; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = ni_660x_dio_insn_bits; - s->insn_config = ni_660x_dio_insn_config; - s->io_bits = 0; /* all bits default to input */ - /* we use the ioconfig registers to control dio direction, so zero - output enables in stc dio control reg */ - ni_660x_write_register(dev, 0, 0, STCDIOControl); - - private(dev)->counter_dev = ni_gpct_device_construct(dev, - &ni_gpct_write_register, - &ni_gpct_read_register, - ni_gpct_variant_660x, - ni_660x_num_counters - (dev)); - if (private(dev)->counter_dev == NULL) - return -ENOMEM; - for (i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i) { - s = dev->subdevices + NI_660X_GPCT_SUBDEV(i); - if (i < ni_660x_num_counters(dev)) { - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = - SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | - SDF_CMD_READ /* | SDF_CMD_WRITE */ ; - s->n_chan = 3; - s->maxdata = 0xffffffff; - s->insn_read = ni_660x_GPCT_rinsn; - s->insn_write = ni_660x_GPCT_winsn; - s->insn_config = ni_660x_GPCT_insn_config; - s->do_cmd = &ni_660x_cmd; - s->len_chanlist = 1; - s->do_cmdtest = &ni_660x_cmdtest; - s->cancel = &ni_660x_cancel; - s->poll = &ni_660x_input_poll; - s->async_dma_dir = DMA_BIDIRECTIONAL; - s->buf_change = &ni_660x_buf_change; - s->private = &private(dev)->counter_dev->counters[i]; - - private(dev)->counter_dev->counters[i].chip_index = - i / counters_per_chip; - private(dev)->counter_dev->counters[i].counter_index = - i % counters_per_chip; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - } - for (i = 0; i < board(dev)->n_chips; ++i) - init_tio_chip(dev, i); - - for (i = 0; i < ni_660x_num_counters(dev); ++i) - ni_tio_init_counter(&private(dev)->counter_dev->counters[i]); - - for (i = 0; i < NUM_PFI_CHANNELS; ++i) { - if (i < min_counter_pfi_chan) - ni_660x_set_pfi_routing(dev, i, pfi_output_select_do); - else - ni_660x_set_pfi_routing(dev, i, - pfi_output_select_counter); - ni_660x_select_pfi_output(dev, i, pfi_output_select_high_Z); - } - /* to be safe, set counterswap bits on tio chips after all the counter - outputs have been set to high impedance mode */ - for (i = 0; i < board(dev)->n_chips; ++i) - set_tio_counterswap(dev, i); - - ret = request_irq(mite_irq(private(dev)->mite), ni_660x_interrupt, - IRQF_SHARED, "ni_660x", dev); - if (ret < 0) { - printk(KERN_WARNING " irq not available\n"); - return ret; - } - dev->irq = mite_irq(private(dev)->mite); - global_interrupt_config_bits = Global_Int_Enable_Bit; - if (board(dev)->n_chips > 1) - global_interrupt_config_bits |= Cascade_Int_Enable_Bit; - ni_660x_write_register(dev, 0, global_interrupt_config_bits, - GlobalInterruptConfigRegister); - printk(KERN_INFO "attached\n"); - return 0; -} - -static int ni_660x_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: ni_660x: remove\n", dev->minor); - - /* Free irq */ - if (dev->irq) - free_irq(dev->irq, dev); - - if (dev->private) { - if (private(dev)->counter_dev) - ni_gpct_device_destroy(private(dev)->counter_dev); - if (private(dev)->mite) { - ni_660x_free_mite_rings(dev); - mite_unsetup(private(dev)->mite); - } - } - return 0; -} - -static int -ni_660x_GPCT_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return ni_tio_rinsn(subdev_to_counter(s), insn, data); -} - static void init_tio_chip(struct comedi_device *dev, int chipset) { + struct ni_660x_private *devpriv = dev->private; unsigned i; /* init dma configuration register */ - private(dev)->dma_configuration_soft_copies[chipset] = 0; + devpriv->dma_configuration_soft_copies[chipset] = 0; for (i = 0; i < MAX_DMA_CHANNEL; ++i) { - private(dev)->dma_configuration_soft_copies[chipset] |= + devpriv->dma_configuration_soft_copies[chipset] |= dma_select_bits(i, dma_selection_none) & dma_select_mask(i); } ni_660x_write_register(dev, chipset, - private(dev)-> - dma_configuration_soft_copies[chipset], - DMAConfigRegister); + devpriv->dma_configuration_soft_copies[chipset], + NI660X_DMA_CFG); for (i = 0; i < NUM_PFI_CHANNELS; ++i) ni_660x_write_register(dev, chipset, 0, IOConfigReg(i)); } -static int -ni_660x_GPCT_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return ni_tio_insn_config(subdev_to_counter(s), insn, data); -} - -static int ni_660x_GPCT_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - return ni_tio_winsn(subdev_to_counter(s), insn, data); -} - -static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - - for (i = 0; i < n_ni_660x_boards; i++) { - if (mite_device_id(mite) == ni_660x_boards[i].dev_id) { - dev->board_ptr = ni_660x_boards + i; - private(dev)->mite = mite; - return 0; - } - } - } - printk(KERN_WARNING "no device found\n"); - mite_list_devices(); - return -EIO; -} - static int ni_660x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1284,20 +921,21 @@ static int ni_660x_dio_insn_bits(struct comedi_device *dev, s->state &= ~(data[0] << base_bitfield_channel); s->state |= (data[0] & data[1]) << base_bitfield_channel; /* Write out the new digital output lines */ - ni_660x_write_register(dev, 0, s->state, DIO32Output); + ni_660x_write_register(dev, 0, s->state, NI660X_DIO32_OUTPUT); } /* on return, data[1] contains the value of the digital * input and output lines. */ - data[1] = - (ni_660x_read_register(dev, 0, - DIO32Input) >> base_bitfield_channel); - return 2; + data[1] = (ni_660x_read_register(dev, 0, NI660X_DIO32_INPUT) >> + base_bitfield_channel); + + return insn->n; } 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); static const unsigned counter_4_7_first_pfi = 8; static const unsigned counter_4_7_last_pfi = 23; unsigned active_chipset = 0; @@ -1305,7 +943,7 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev, unsigned active_bits; unsigned idle_bits; - if (board(dev)->n_chips > 1) { + if (board->n_chips > 1) { if (output_select == pfi_output_select_counter && pfi_channel >= counter_4_7_first_pfi && pfi_channel <= counter_4_7_last_pfi) { @@ -1341,6 +979,8 @@ static void ni_660x_select_pfi_output(struct comedi_device *dev, static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { + struct ni_660x_private *devpriv = dev->private; + if (source > num_pfi_output_selects) return -EINVAL; if (source == pfi_output_select_high_Z) @@ -1352,76 +992,249 @@ static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan, if (source == pfi_output_select_do) return -EINVAL; } - BUG_ON(chan >= NUM_PFI_CHANNELS); - private(dev)->pfi_output_selects[chan] = source; - if (private(dev)->pfi_direction_bits & (((uint64_t) 1) << chan)) + devpriv->pfi_output_selects[chan] = source; + if (devpriv->pfi_direction_bits & (((uint64_t) 1) << chan)) ni_660x_select_pfi_output(dev, chan, - private(dev)-> - pfi_output_selects[chan]); + devpriv->pfi_output_selects[chan]); return 0; } -static unsigned ni_660x_get_pfi_routing(struct comedi_device *dev, - unsigned chan) -{ - BUG_ON(chan >= NUM_PFI_CHANNELS); - return private(dev)->pfi_output_selects[chan]; -} - -static void ni660x_config_filter(struct comedi_device *dev, - unsigned pfi_channel, - enum ni_gpct_filter_select filter) -{ - unsigned bits = ni_660x_read_register(dev, 0, IOConfigReg(pfi_channel)); - bits &= ~pfi_input_select_mask(pfi_channel); - bits |= pfi_input_select_bits(pfi_channel, filter); - ni_660x_write_register(dev, 0, bits, IOConfigReg(pfi_channel)); -} - static int ni_660x_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); - - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ + struct ni_660x_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + uint64_t bit = 1ULL << chan; + unsigned int val; + int ret; switch (data[0]) { case INSN_CONFIG_DIO_OUTPUT: - private(dev)->pfi_direction_bits |= ((uint64_t) 1) << chan; + devpriv->pfi_direction_bits |= bit; ni_660x_select_pfi_output(dev, chan, - private(dev)-> - pfi_output_selects[chan]); + devpriv->pfi_output_selects[chan]); break; + case INSN_CONFIG_DIO_INPUT: - private(dev)->pfi_direction_bits &= ~(((uint64_t) 1) << chan); + devpriv->pfi_direction_bits &= ~bit; ni_660x_select_pfi_output(dev, chan, pfi_output_select_high_Z); break; + case INSN_CONFIG_DIO_QUERY: - data[1] = - (private(dev)->pfi_direction_bits & - (((uint64_t) 1) << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return 0; + data[1] = (devpriv->pfi_direction_bits & bit) ? COMEDI_OUTPUT + : COMEDI_INPUT; + break; + case INSN_CONFIG_SET_ROUTING: - return ni_660x_set_pfi_routing(dev, chan, data[1]); + ret = ni_660x_set_pfi_routing(dev, chan, data[1]); + if (ret) + return ret; break; + case INSN_CONFIG_GET_ROUTING: - data[1] = ni_660x_get_pfi_routing(dev, chan); + data[1] = devpriv->pfi_output_selects[chan]; break; + case INSN_CONFIG_FILTER: - ni660x_config_filter(dev, chan, data[1]); + val = ni_660x_read_register(dev, 0, IOConfigReg(chan)); + val &= ~pfi_input_select_mask(chan); + val |= pfi_input_select_bits(chan, data[1]); + ni_660x_write_register(dev, 0, val, IOConfigReg(chan)); break; + default: return -EINVAL; - break; } + + return insn->n; +} + +static int ni_660x_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct ni_660x_board *board = NULL; + struct ni_660x_private *devpriv; + struct comedi_subdevice *s; + int ret; + unsigned i; + unsigned global_interrupt_config_bits; + + if (context < ARRAY_SIZE(ni_660x_boards)) + board = &ni_660x_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + ret = ni_660x_allocate_private(dev); + if (ret < 0) + return ret; + devpriv = dev->private; + + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; + + ret = mite_setup2(devpriv->mite, 1); + if (ret < 0) { + dev_warn(dev->class_dev, "error setting up mite\n"); + return ret; + } + + ret = ni_660x_alloc_mite_rings(dev); + if (ret < 0) + return ret; + + ret = comedi_alloc_subdevices(dev, 2 + NI_660X_MAX_NUM_COUNTERS); + if (ret) + return ret; + + s = &dev->subdevices[0]; + /* Old GENERAL-PURPOSE COUNTER/TIME (GPCT) subdevice, no longer used */ + s->type = COMEDI_SUBD_UNUSED; + + s = &dev->subdevices[NI_660X_DIO_SUBDEV]; + /* DIGITAL I/O SUBDEVICE */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = NUM_PFI_CHANNELS; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = ni_660x_dio_insn_bits; + s->insn_config = ni_660x_dio_insn_config; + /* we use the ioconfig registers to control dio direction, so zero + output enables in stc dio control reg */ + ni_660x_write_register(dev, 0, 0, NI660X_STC_DIO_CONTROL); + + devpriv->counter_dev = ni_gpct_device_construct(dev, + &ni_gpct_write_register, + &ni_gpct_read_register, + ni_gpct_variant_660x, + ni_660x_num_counters + (dev)); + if (devpriv->counter_dev == NULL) + return -ENOMEM; + for (i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i) { + s = &dev->subdevices[NI_660X_GPCT_SUBDEV(i)]; + if (i < ni_660x_num_counters(dev)) { + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = + SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | + SDF_CMD_READ /* | SDF_CMD_WRITE */ ; + s->n_chan = 3; + s->maxdata = 0xffffffff; + s->insn_read = ni_tio_insn_read; + s->insn_write = ni_tio_insn_write; + s->insn_config = ni_tio_insn_config; + s->do_cmd = &ni_660x_cmd; + s->len_chanlist = 1; + s->do_cmdtest = ni_tio_cmdtest; + s->cancel = &ni_660x_cancel; + s->poll = &ni_660x_input_poll; + s->async_dma_dir = DMA_BIDIRECTIONAL; + s->buf_change = &ni_660x_buf_change; + s->private = &devpriv->counter_dev->counters[i]; + + devpriv->counter_dev->counters[i].chip_index = + i / counters_per_chip; + devpriv->counter_dev->counters[i].counter_index = + i % counters_per_chip; + } else { + s->type = COMEDI_SUBD_UNUSED; + } + } + for (i = 0; i < board->n_chips; ++i) + init_tio_chip(dev, i); + + for (i = 0; i < ni_660x_num_counters(dev); ++i) + ni_tio_init_counter(&devpriv->counter_dev->counters[i]); + + for (i = 0; i < NUM_PFI_CHANNELS; ++i) { + if (i < min_counter_pfi_chan) + ni_660x_set_pfi_routing(dev, i, pfi_output_select_do); + else + ni_660x_set_pfi_routing(dev, i, + pfi_output_select_counter); + ni_660x_select_pfi_output(dev, i, pfi_output_select_high_Z); + } + /* to be safe, set counterswap bits on tio chips after all the counter + outputs have been set to high impedance mode */ + for (i = 0; i < board->n_chips; ++i) + set_tio_counterswap(dev, i); + + ret = request_irq(mite_irq(devpriv->mite), ni_660x_interrupt, + IRQF_SHARED, "ni_660x", dev); + if (ret < 0) { + dev_warn(dev->class_dev, " irq not available\n"); + return ret; + } + dev->irq = mite_irq(devpriv->mite); + global_interrupt_config_bits = Global_Int_Enable_Bit; + if (board->n_chips > 1) + global_interrupt_config_bits |= Cascade_Int_Enable_Bit; + ni_660x_write_register(dev, 0, global_interrupt_config_bits, + NI660X_GLOBAL_INT_CFG); + return 0; } +static void ni_660x_detach(struct comedi_device *dev) +{ + struct ni_660x_private *devpriv = dev->private; + + if (dev->irq) + free_irq(dev->irq, dev); + if (devpriv) { + if (devpriv->counter_dev) + ni_gpct_device_destroy(devpriv->counter_dev); + if (devpriv->mite) { + ni_660x_free_mite_rings(dev); + mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); + } + } + comedi_pci_disable(dev); +} + +static struct comedi_driver ni_660x_driver = { + .driver_name = "ni_660x", + .module = THIS_MODULE, + .auto_attach = ni_660x_auto_attach, + .detach = ni_660x_detach, +}; + +static int ni_660x_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &ni_660x_driver, id->driver_data); +} + +static const struct pci_device_id ni_660x_pci_table[] = { + { PCI_VDEVICE(NI, 0x1310), BOARD_PCI6602 }, + { PCI_VDEVICE(NI, 0x1360), BOARD_PXI6602 }, + { PCI_VDEVICE(NI, 0x2c60), BOARD_PCI6601 }, + { PCI_VDEVICE(NI, 0x2cc0), BOARD_PXI6608 }, + { PCI_VDEVICE(NI, 0x1e40), BOARD_PXI6624 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ni_660x_pci_table); + +static struct pci_driver ni_660x_pci_driver = { + .name = "ni_660x", + .id_table = ni_660x_pci_table, + .probe = ni_660x_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(ni_660x_driver, ni_660x_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index d8d91f90060..1002ceacfdc 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_670x @@ -41,8 +36,10 @@ Commands are not supported. */ +#include <linux/module.h> +#include <linux/pci.h> #include <linux/interrupt.h> -#include <linux/slab.h> + #include "../comedidev.h" #include "mite.h" @@ -58,46 +55,32 @@ Commands are not supported. #define MISC_STATUS_OFFSET 0x14 #define MISC_CONTROL_OFFSET 0x14 -/* Board description*/ +enum ni_670x_boardid { + BOARD_PCI6703, + BOARD_PXI6704, + BOARD_PCI6704, +}; struct ni_670x_board { - unsigned short dev_id; const char *name; unsigned short ao_chans; - unsigned short ao_bits; }; static const struct ni_670x_board ni_670x_boards[] = { - { - .dev_id = 0x2c90, - .name = "PCI-6703", - .ao_chans = 16, - .ao_bits = 16, - }, - { - .dev_id = 0x1920, - .name = "PXI-6704", - .ao_chans = 32, - .ao_bits = 16, - }, - { - .dev_id = 0x1290, - .name = "PCI-6704", - .ao_chans = 32, - .ao_bits = 16, - }, -}; - -static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c90)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1920)}, - {0} + [BOARD_PCI6703] = { + .name = "PCI-6703", + .ao_chans = 16, + }, + [BOARD_PXI6704] = { + .name = "PXI-6704", + .ao_chans = 32, + }, + [BOARD_PCI6704] = { + .name = "PCI-6704", + .ao_chans = 32, + }, }; -MODULE_DEVICE_TABLE(pci, ni_670x_pci_table); - -#define thisboard ((struct ni_670x_board *)dev->board_ptr) - struct ni_670x_private { struct mite_struct *mite; @@ -106,106 +89,125 @@ struct ni_670x_private { unsigned int ao_readback[32]; }; -#define devpriv ((struct ni_670x_private *)dev->private) -#define n_ni_670x_boards ARRAY_SIZE(ni_670x_boards) +static int ni_670x_ao_winsn(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); -static int ni_670x_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int ni_670x_detach(struct comedi_device *dev); + /* Channel number mapping : -static struct comedi_driver driver_ni_670x = { - .driver_name = "ni_670x", - .module = THIS_MODULE, - .attach = ni_670x_attach, - .detach = ni_670x_detach, -}; + 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 */ -static int __devinit driver_ni_670x_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_ni_670x.driver_name); -} + for (i = 0; i < insn->n; i++) { + /* First write in channel register which channel to use */ + writel(((chan & 15) << 1) | ((chan & 16) >> 4), + devpriv->mite->daq_io_addr + AO_CHAN_OFFSET); + /* write channel value */ + writel(data[i], devpriv->mite->daq_io_addr + AO_VALUE_OFFSET); + devpriv->ao_readback[chan] = data[i]; + } -static void __devexit driver_ni_670x_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); + return i; } -static struct pci_driver driver_ni_670x_pci_driver = { - .id_table = ni_670x_pci_table, - .probe = &driver_ni_670x_pci_probe, - .remove = __devexit_p(&driver_ni_670x_pci_remove) -}; - -static int __init driver_ni_670x_init_module(void) +static int ni_670x_ao_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int retval; + struct ni_670x_private *devpriv = dev->private; + int i; + int chan = CR_CHAN(insn->chanspec); - retval = comedi_driver_register(&driver_ni_670x); - if (retval < 0) - return retval; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - driver_ni_670x_pci_driver.name = (char *)driver_ni_670x.driver_name; - return pci_register_driver(&driver_ni_670x_pci_driver); + return i; } -static void __exit driver_ni_670x_cleanup_module(void) +static int ni_670x_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - pci_unregister_driver(&driver_ni_670x_pci_driver); - comedi_driver_unregister(&driver_ni_670x); -} + struct ni_670x_private *devpriv = dev->private; + void __iomem *io_addr = devpriv->mite->daq_io_addr + + DIO_PORT0_DATA_OFFSET; -module_init(driver_ni_670x_init_module); -module_exit(driver_ni_670x_cleanup_module); + if (comedi_dio_update_state(s, data)) + writel(s->state, io_addr); -static struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} }; + data[1] = readl(io_addr); -static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot); + return insn->n; +} -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_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ni_670x_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); static int ni_670x_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); + unsigned int *data) +{ + struct ni_670x_private *devpriv = dev->private; + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; + + writel(s->io_bits, devpriv->mite->daq_io_addr + DIO_PORT0_DIR_OFFSET); -static int ni_670x_attach(struct comedi_device *dev, - struct comedi_devconfig *it) + return insn->n; +} + +static int ni_670x_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct ni_670x_board *thisboard = NULL; + struct ni_670x_private *devpriv; struct comedi_subdevice *s; int ret; int i; - printk(KERN_INFO "comedi%d: ni_670x: ", dev->minor); + if (context < ARRAY_SIZE(ni_670x_boards)) + thisboard = &ni_670x_boards[context]; + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; - ret = alloc_private(dev, sizeof(struct ni_670x_private)); - if (ret < 0) + ret = comedi_pci_enable(dev); + if (ret) return ret; - ret = ni_670x_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; ret = mite_setup(devpriv->mite); if (ret < 0) { - printk(KERN_WARNING "error setting up mite\n"); + dev_warn(dev->class_dev, "error setting up mite\n"); return ret; } - dev->board_name = thisboard->name; - dev->irq = mite_irq(devpriv->mite); - printk(KERN_INFO " %s", dev->board_name); - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -229,7 +231,7 @@ static int ni_670x_attach(struct comedi_device *dev, s->insn_write = &ni_670x_ao_winsn; s->insn_read = &ni_670x_ao_rinsn; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -244,146 +246,54 @@ static int ni_670x_attach(struct comedi_device *dev, /* Config of ao registers */ writel(0x00, devpriv->mite->daq_io_addr + AO_CONTROL_OFFSET); - printk(KERN_INFO "attached\n"); - - return 1; -} - -static int ni_670x_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: ni_670x: remove\n", dev->minor); - - kfree(dev->subdevices[0].range_table_list); - - if (dev->private && devpriv->mite) - mite_unsetup(devpriv->mite); - - if (dev->irq) - free_irq(dev->irq, dev); - return 0; } -static int ni_670x_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void ni_670x_detach(struct comedi_device *dev) { - 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 */ + struct ni_670x_private *devpriv = dev->private; + struct comedi_subdevice *s; - for (i = 0; i < insn->n; i++) { - /* First write in channel register which channel to use */ - writel(((chan & 15) << 1) | ((chan & 16) >> 4), - devpriv->mite->daq_io_addr + AO_CHAN_OFFSET); - /* write channel value */ - writel(data[i], devpriv->mite->daq_io_addr + AO_VALUE_OFFSET); - devpriv->ao_readback[chan] = data[i]; + if (dev->n_subdevices) { + s = &dev->subdevices[0]; + if (s) + kfree(s->range_table_list); } - - return i; -} - -static int ni_670x_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - 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 ni_670x_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - writel(s->state, - devpriv->mite->daq_io_addr + DIO_PORT0_DATA_OFFSET); + if (devpriv && devpriv->mite) { + mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); } - - /* on return, data[1] contains the value of the digital - * input lines. */ - data[1] = readl(devpriv->mite->daq_io_addr + DIO_PORT0_DATA_OFFSET); - - return 2; + comedi_pci_disable(dev); } -static int ni_670x_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << chan; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << chan); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } - writel(s->io_bits, devpriv->mite->daq_io_addr + DIO_PORT0_DIR_OFFSET); - - return insn->n; -} +static struct comedi_driver ni_670x_driver = { + .driver_name = "ni_670x", + .module = THIS_MODULE, + .auto_attach = ni_670x_auto_attach, + .detach = ni_670x_detach, +}; -static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot) +static int ni_670x_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number - || slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } + return comedi_pci_auto_config(dev, &ni_670x_driver, id->driver_data); +} - for (i = 0; i < n_ni_670x_boards; i++) { - if (mite_device_id(mite) == ni_670x_boards[i].dev_id) { - dev->board_ptr = ni_670x_boards + i; - devpriv->mite = mite; +static const struct pci_device_id ni_670x_pci_table[] = { + { PCI_VDEVICE(NI, 0x1290), BOARD_PCI6704 }, + { PCI_VDEVICE(NI, 0x1920), BOARD_PXI6704 }, + { PCI_VDEVICE(NI, 0x2c90), BOARD_PCI6703 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ni_670x_pci_table); - return 0; - } - } - } - printk(KERN_INFO "no device found\n"); - mite_list_devices(); - return -EIO; -} +static struct pci_driver ni_670x_pci_driver = { + .name = "ni_670x", + .id_table = ni_670x_pci_table, + .probe = ni_670x_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(ni_670x_driver, ni_670x_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index c192b71ec04..5bd19494dbf 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -15,12 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: ni_at_a2150 @@ -64,11 +58,14 @@ TRIG_WAKE_EOS */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/slab.h> #include "../comedidev.h" -#include <linux/ioport.h> +#include <linux/io.h> + #include <asm/dma.h> #include "8253.h" @@ -77,9 +74,6 @@ TRIG_WAKE_EOS #define A2150_SIZE 28 #define A2150_DMA_BUFFER_SIZE 0xff00 /* size in bytes of dma buffer */ -/* #define A2150_DEBUG enable debugging code */ -#undef A2150_DEBUG /* disable debugging code */ - /* Registers and bits */ #define CONFIG_REG 0x0 #define CHANNEL_BITS(x) ((x) & 0x7) @@ -130,10 +124,9 @@ struct a2150_board { /* analog input range */ static const struct comedi_lrange range_a2150 = { - 1, - { - RANGE(-2.828, 2.828), - } + 1, { + BIP_RANGE(2.828) + } }; /* enum must match board indices */ @@ -153,74 +146,23 @@ static const struct a2150_board a2150_boards[] = { }, }; -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct a2150_board *)dev->board_ptr) - struct a2150_private { volatile unsigned int count; /* number of data points left to be taken */ unsigned int dma; /* dma channel */ - s16 *dma_buffer; /* dma buffer */ + uint16_t *dma_buffer; /* dma buffer */ unsigned int dma_transfer_size; /* size in bytes of dma transfers */ int irq_dma_bits; /* irq/dma register bits */ int config_bits; /* config register bits */ }; -#define devpriv ((struct a2150_private *)dev->private) - -static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int a2150_detach(struct comedi_device *dev); static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static struct comedi_driver driver_a2150 = { - .driver_name = "ni_at_a2150", - .module = THIS_MODULE, - .attach = a2150_attach, - .detach = a2150_detach, -}; - -static irqreturn_t a2150_interrupt(int irq, void *d); -static int a2150_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, int flags); -static int a2150_probe(struct comedi_device *dev); static int a2150_set_chanlist(struct comedi_device *dev, unsigned int start_channel, unsigned int num_channels); -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_a2150_init_module(void) -{ - return comedi_driver_register(&driver_a2150); -} - -static void __exit driver_a2150_cleanup_module(void) -{ - comedi_driver_unregister(&driver_a2150); -} - -module_init(driver_a2150_init_module); -module_exit(driver_a2150_cleanup_module); - -#ifdef A2150_DEBUG - -static void ni_dump_regs(struct comedi_device *dev) -{ - printk("config bits 0x%x\n", devpriv->config_bits); - printk("irq dma bits 0x%x\n", devpriv->irq_dma_bits); - printk("status bits 0x%x\n", inw(dev->iobase + STATUS_REG)); -} - -#endif - /* interrupt service routine */ static irqreturn_t a2150_interrupt(int irq, void *d) { @@ -228,20 +170,20 @@ static irqreturn_t a2150_interrupt(int irq, void *d) int status; unsigned long flags; struct comedi_device *dev = d; + struct a2150_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async; struct comedi_cmd *cmd; unsigned int max_points, num_points, residue, leftover; - short dpnt; + unsigned short dpnt; static const int sample_size = sizeof(devpriv->dma_buffer[0]); - if (dev->attached == 0) { + if (!dev->attached) { comedi_error(dev, "premature interrupt"); return IRQ_HANDLED; } /* initialize async here to make sure s is not NULL */ async = s->async; - async->events = 0; cmd = &async->cmd; status = inw(dev->iobase + STATUS_REG); @@ -253,15 +195,14 @@ static irqreturn_t a2150_interrupt(int irq, void *d) if (status & OVFL_BIT) { comedi_error(dev, "fifo overflow"); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; + cfc_handle_events(dev, s); } if ((status & DMA_TC_BIT) == 0) { comedi_error(dev, "caught non-dma interrupt? Aborting."); - a2150_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } @@ -306,7 +247,6 @@ static irqreturn_t a2150_interrupt(int irq, void *d) cfc_write_to_buffer(s, dpnt); if (cmd->stop_src == TRIG_COUNT) { if (--devpriv->count == 0) { /* end of acquisition */ - a2150_cancel(dev, s); async->events |= COMEDI_CB_EOA; break; } @@ -322,7 +262,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d) async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); /* clear interrupt */ outw(0x00, dev->iobase + DMA_TC_CLEAR_REG); @@ -330,255 +270,108 @@ static irqreturn_t a2150_interrupt(int irq, void *d) return IRQ_HANDLED; } -/* probes board type, returns offset */ -static int a2150_probe(struct comedi_device *dev) +static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - int status = inw(dev->iobase + STATUS_REG); - return ID_BITS(status); + struct a2150_private *devpriv = dev->private; + + /* disable dma on card */ + devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT; + outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); + + /* disable computer's dma */ + disable_dma(devpriv->dma); + + /* clear fifo and reset triggering circuitry */ + outw(0, dev->iobase + FIFO_RESET_REG); + + return 0; } -static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int a2150_ai_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - struct comedi_subdevice *s; - unsigned long iobase = it->options[0]; - unsigned int irq = it->options[1]; - unsigned int dma = it->options[2]; - static const int timeout = 2000; + unsigned int chan0 = CR_CHAN(cmd->chanlist[0]); + unsigned int aref0 = CR_AREF(cmd->chanlist[0]); int i; - printk("comedi%d: %s: io 0x%lx", dev->minor, driver_a2150.driver_name, - iobase); - if (irq) { - printk(", irq %u", irq); - } else { - printk(", no irq"); - } - if (dma) { - printk(", dma %u", dma); - } else { - printk(", no dma"); + if (cmd->chanlist_len == 2 && (chan0 == 1 || chan0 == 3)) { + dev_dbg(dev->class_dev, + "length 2 chanlist must be channels 0,1 or channels 2,3\n"); + return -EINVAL; } - printk("\n"); - - /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(struct a2150_private)) < 0) - return -ENOMEM; - if (iobase == 0) { - printk(" io base address required\n"); + if (cmd->chanlist_len == 3) { + dev_dbg(dev->class_dev, + "chanlist must have 1,2 or 4 channels\n"); return -EINVAL; } - /* check if io addresses are available */ - if (!request_region(iobase, A2150_SIZE, driver_a2150.driver_name)) { - printk(" I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; + for (i = 1; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int aref = CR_AREF(cmd->chanlist[i]); - /* grab our IRQ */ - if (irq) { - /* check that irq is supported */ - if (irq < 3 || irq == 8 || irq == 13 || irq > 15) { - printk(" invalid irq line %u\n", irq); + if (chan != (chan0 + i)) { + dev_dbg(dev->class_dev, + "entries in chanlist must be consecutive channels, counting upwards\n"); return -EINVAL; } - if (request_irq(irq, a2150_interrupt, 0, - driver_a2150.driver_name, dev)) { - printk("unable to allocate irq %u\n", irq); - return -EINVAL; - } - devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); - dev->irq = irq; - } - /* initialize dma */ - if (dma) { - if (dma == 4 || dma > 7) { - printk(" invalid dma channel %u\n", dma); - return -EINVAL; - } - if (request_dma(dma, driver_a2150.driver_name)) { - printk(" failed to allocate dma channel %u\n", dma); + + if (chan == 2) + aref0 = aref; + if (aref != aref0) { + dev_dbg(dev->class_dev, + "channels 0/1 and 2/3 must have the same analog reference\n"); return -EINVAL; } - devpriv->dma = dma; - devpriv->dma_buffer = - kmalloc(A2150_DMA_BUFFER_SIZE, GFP_KERNEL | GFP_DMA); - if (devpriv->dma_buffer == NULL) - return -ENOMEM; - - disable_dma(dma); - set_dma_mode(dma, DMA_MODE_READ); - - devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma); - } - - dev->board_ptr = a2150_boards + a2150_probe(dev); - dev->board_name = thisboard->name; - - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - - /* analog input subdevice */ - s = dev->subdevices + 0; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ; - s->n_chan = 4; - s->len_chanlist = 4; - s->maxdata = 0xffff; - s->range_table = &range_a2150; - s->do_cmd = a2150_ai_cmd; - s->do_cmdtest = a2150_ai_cmdtest; - s->insn_read = a2150_ai_rinsn; - s->cancel = a2150_cancel; - - /* need to do this for software counting of completed conversions, to - * prevent hardware count from stopping acquisition */ - outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG); - - /* set card's irq and dma levels */ - outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); - - /* reset and sync adc clock circuitry */ - outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG); - outw_p(DPD_BIT, dev->iobase + CONFIG_REG); - /* initialize configuration register */ - devpriv->config_bits = 0; - outw(devpriv->config_bits, dev->iobase + CONFIG_REG); - /* wait until offset calibration is done, then enable analog inputs */ - for (i = 0; i < timeout; i++) { - if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0) - break; - udelay(1000); - } - if (i == timeout) { - printk - (" timed out waiting for offset calibration to complete\n"); - return -ETIME; - } - devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT; - outw(devpriv->config_bits, dev->iobase + CONFIG_REG); - - return 0; -}; - -static int a2150_detach(struct comedi_device *dev) -{ - printk("comedi%d: %s: remove\n", dev->minor, driver_a2150.driver_name); - - /* only free stuff if it has been allocated by _attach */ - if (dev->iobase) { - /* put board in power-down mode */ - outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG); - release_region(dev->iobase, A2150_SIZE); - } - - if (dev->irq) - free_irq(dev->irq, dev); - if (devpriv) { - if (devpriv->dma) - free_dma(devpriv->dma); - kfree(devpriv->dma_buffer); } return 0; -}; - -static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - /* disable dma on card */ - devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT; - outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); - - /* disable computer's dma */ - disable_dma(devpriv->dma); - - /* clear fifo and reset triggering circuitry */ - outw(0, dev->iobase + FIFO_RESET_REG); - - return 0; } static int a2150_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct a2150_board *thisboard = comedi_board(dev); int err = 0; - int tmp; - int startChan; - int i; + unsigned int arg; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, 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_NONE); - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + if (err) + return 1; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 2a : make sure trigger sources are unique */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + /* Step 2b : and mutually compatible */ if (err) - return 1; + return 2; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (err) - return 2; + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + thisboard->ai_speed); - /* step 3: make sure arguments are trivially compatible */ + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < thisboard->ai_speed) { - cmd->convert_arg = thisboard->ai_speed; - err++; - } - } - if (!cmd->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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; @@ -586,42 +379,17 @@ static int a2150_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - a2150_get_timing(dev, &cmd->scan_begin_arg, cmd->flags); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + a2150_get_timing(dev, &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) return 4; - /* check channel/gain list against card's limitations */ - if (cmd->chanlist) { - startChan = CR_CHAN(cmd->chanlist[0]); - for (i = 1; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) != (startChan + i)) { - comedi_error(dev, - "entries in chanlist must be consecutive channels, counting upwards\n"); - err++; - } - } - if (cmd->chanlist_len == 2 && CR_CHAN(cmd->chanlist[0]) == 1) { - comedi_error(dev, - "length 2 chanlist must be channels 0,1 or channels 2,3"); - err++; - } - if (cmd->chanlist_len == 3) { - comedi_error(dev, - "chanlist must have 1,2 or 4 channels"); - err++; - } - if (CR_AREF(cmd->chanlist[0]) != CR_AREF(cmd->chanlist[1]) || - CR_AREF(cmd->chanlist[2]) != CR_AREF(cmd->chanlist[3])) { - comedi_error(dev, - "channels 0/1 and 2/3 must have the same analog reference"); - err++; - } - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= a2150_ai_check_chanlist(dev, s, cmd); if (err) return 5; @@ -631,17 +399,14 @@ static int a2150_ai_cmdtest(struct comedi_device *dev, static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct a2150_private *devpriv = dev->private; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; + unsigned long timer_base = dev->iobase + I8253_BASE_REG; unsigned long lock_flags; unsigned int old_config_bits = devpriv->config_bits; unsigned int trigger_bits; - if (!dev->irq || !devpriv->dma) { - comedi_error(dev, - " irq and dma required, cannot do hardware conversions"); - return -1; - } if (cmd->flags & TRIG_RT) { comedi_error(dev, " dma incompatible with hard real-time interrupt (TRIG_RT), aborting"); @@ -705,7 +470,8 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); /* may need to wait 72 sampling periods if timing was changed */ - i8254_load(dev->iobase + I8253_BASE_REG, 0, 2, 72, 0); + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_write(timer_base, 0, 2, 72); /* setup start triggering */ trigger_bits = 0; @@ -730,22 +496,31 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) outw(trigger_bits, dev->iobase + TRIGGER_REG); /* start acquisition for soft trigger */ - if (cmd->start_src == TRIG_NOW) { + if (cmd->start_src == TRIG_NOW) outw(0, dev->iobase + FIFO_START_REG); - } -#ifdef A2150_DEBUG - ni_dump_regs(dev); -#endif return 0; } +static int a2150_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STATUS_REG); + if (status & FNE_BIT) + return 0; + return -EBUSY; +} + static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - unsigned int i, n; - static const int timeout = 100000; - static const int filter_delay = 36; + struct a2150_private *devpriv = dev->private; + unsigned int n; + int ret; /* clear fifo and reset triggering circuitry */ outw(0, dev->iobase + FIFO_RESET_REG); @@ -771,38 +546,25 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* start acquisition for soft trigger */ outw(0, dev->iobase + FIFO_START_REG); - /* there is a 35.6 sample delay for data to get through the antialias filter */ - for (n = 0; n < filter_delay; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } + /* + * there is a 35.6 sample delay for data to get through the + * antialias filter + */ + for (n = 0; n < 36; n++) { + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + inw(dev->iobase + FIFO_DATA_REG); } /* read data */ for (n = 0; n < insn->n; n++) { - for (i = 0; i < timeout; i++) { - if (inw(dev->iobase + STATUS_REG) & FNE_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } -#ifdef A2150_DEBUG - ni_dump_regs(dev); -#endif + ret = comedi_timeout(dev, s, insn, a2150_ai_eoc, 0); + if (ret) + return ret; + data[n] = inw(dev->iobase + FIFO_DATA_REG); -#ifdef A2150_DEBUG - printk(" data is %i\n", data[n]); -#endif data[n] ^= 0x8000; } @@ -812,11 +574,15 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return n; } -/* sets bits in devpriv->clock_bits to nearest approximation of requested period, - * adjusts requested period to actual timing. */ +/* + * sets bits in devpriv->clock_bits to nearest approximation of requested + * period, adjusts requested period to actual timing. + */ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, int flags) { + const struct a2150_board *thisboard = comedi_board(dev); + struct a2150_private *devpriv = dev->private; int lub, glb, temp; int lub_divisor_shift, lub_index, glb_divisor_shift, glb_index; int i, j; @@ -859,11 +625,10 @@ static int a2150_get_timing(struct comedi_device *dev, unsigned int *period, case TRIG_ROUND_NEAREST: default: /* if least upper bound is better approximation */ - if (lub - *period < *period - glb) { + if (lub - *period < *period - glb) *period = lub; - } else { + else *period = glb; - } break; case TRIG_ROUND_UP: *period = lub; @@ -892,6 +657,8 @@ static int a2150_set_chanlist(struct comedi_device *dev, unsigned int start_channel, unsigned int num_channels) { + struct a2150_private *devpriv = dev->private; + if (start_channel + num_channels > 4) return -1; @@ -902,13 +669,12 @@ static int a2150_set_chanlist(struct comedi_device *dev, devpriv->config_bits |= CHANNEL_BITS(0x4 | start_channel); break; case 2: - if (start_channel == 0) { + if (start_channel == 0) devpriv->config_bits |= CHANNEL_BITS(0x2); - } else if (start_channel == 2) { + else if (start_channel == 2) devpriv->config_bits |= CHANNEL_BITS(0x3); - } else { + else return -1; - } break; case 4: devpriv->config_bits |= CHANNEL_BITS(0x1); @@ -921,6 +687,135 @@ static int a2150_set_chanlist(struct comedi_device *dev, return 0; } +/* probes board type, returns offset */ +static int a2150_probe(struct comedi_device *dev) +{ + int status = inw(dev->iobase + STATUS_REG); + return ID_BITS(status); +} + +static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + const struct a2150_board *thisboard; + struct a2150_private *devpriv; + struct comedi_subdevice *s; + unsigned int irq = it->options[1]; + unsigned int dma = it->options[2]; + static const int timeout = 2000; + int i; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_request_region(dev, it->options[0], A2150_SIZE); + if (ret) + return ret; + + dev->board_ptr = a2150_boards + a2150_probe(dev); + thisboard = comedi_board(dev); + dev->board_name = thisboard->name; + + if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) || + irq == 14 || irq == 15) { + ret = request_irq(irq, a2150_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq); + dev->irq = irq; + } + } + + if (dev->irq && dma <= 7 && dma != 4) { + ret = request_dma(dma, dev->board_name); + if (ret == 0) { + devpriv->dma = dma; + devpriv->dma_buffer = kmalloc(A2150_DMA_BUFFER_SIZE, + GFP_KERNEL | GFP_DMA); + if (!devpriv->dma_buffer) + return -ENOMEM; + + disable_dma(dma); + set_dma_mode(dma, DMA_MODE_READ); + + devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma); + } + } + + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + /* analog input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER; + s->n_chan = 4; + s->maxdata = 0xffff; + s->range_table = &range_a2150; + s->insn_read = a2150_ai_rinsn; + if (dev->irq && devpriv->dma) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmd = a2150_ai_cmd; + s->do_cmdtest = a2150_ai_cmdtest; + s->cancel = a2150_cancel; + } + + /* need to do this for software counting of completed conversions, to + * prevent hardware count from stopping acquisition */ + outw(HW_COUNT_DISABLE, dev->iobase + I8253_MODE_REG); + + /* set card's irq and dma levels */ + outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG); + + /* reset and sync adc clock circuitry */ + outw_p(DPD_BIT | APD_BIT, dev->iobase + CONFIG_REG); + outw_p(DPD_BIT, dev->iobase + CONFIG_REG); + /* initialize configuration register */ + devpriv->config_bits = 0; + outw(devpriv->config_bits, dev->iobase + CONFIG_REG); + /* wait until offset calibration is done, then enable analog inputs */ + for (i = 0; i < timeout; i++) { + if ((DCAL_BIT & inw(dev->iobase + STATUS_REG)) == 0) + break; + udelay(1000); + } + if (i == timeout) { + printk + (" timed out waiting for offset calibration to complete\n"); + return -ETIME; + } + devpriv->config_bits |= ENABLE0_BIT | ENABLE1_BIT; + outw(devpriv->config_bits, dev->iobase + CONFIG_REG); + + return 0; +}; + +static void a2150_detach(struct comedi_device *dev) +{ + struct a2150_private *devpriv = dev->private; + + if (dev->iobase) + outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG); + if (devpriv) { + if (devpriv->dma) + free_dma(devpriv->dma); + kfree(devpriv->dma_buffer); + } + comedi_legacy_detach(dev); +}; + +static struct comedi_driver ni_at_a2150_driver = { + .driver_name = "ni_at_a2150", + .module = THIS_MODULE, + .attach = a2150_attach, + .detach = a2150_detach, +}; +module_comedi_driver(ni_at_a2150_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index 138dcc2275a..c93b47bcca5 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -1,157 +1,104 @@ /* - comedi/drivers/ni_at_ao.c - Driver for NI AT-AO-6/10 boards + * ni_at_ao.c + * Driver for NI AT-AO-6/10 boards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000,2002 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000,2002 David A. Schleef <ds@schleef.org> +/* + * Driver: ni_at_ao + * Description: National Instruments AT-AO-6/10 + * Devices: (National Instruments) AT-AO-6 [at-ao-6] + * (National Instruments) AT-AO-10 [at-ao-10] + * Status: should work + * Author: David A. Schleef <ds@schleef.org> + * Updated: Sun Dec 26 12:26:28 EST 2004 + * + * Configuration options: + * [0] - I/O port base address + * [1] - IRQ (unused) + * [2] - DMA (unused) + * [3] - analog output range, set by jumpers on hardware + * 0 for -10 to 10V bipolar + * 1 for 0V to 10V unipolar + */ - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. +#include <linux/module.h> - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +#include "../comedidev.h" - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +#include "8253.h" -*/ -/* -Driver: ni_at_ao -Description: National Instruments AT-AO-6/10 -Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10) -Status: should work -Author: ds -Updated: Sun Dec 26 12:26:28 EST 2004 - -Configuration options: - [0] - I/O port base address - [1] - IRQ (unused) - [2] - DMA (unused) - [3] - analog output range, set by jumpers on hardware (0 for -10 to 10V - bipolar, 1 for 0V to 10V unipolar) - -*/ /* + * Register map + * * Register-level programming information can be found in NI * document 320379.pdf. */ +#define ATAO_DIO_REG 0x00 +#define ATAO_CFG2_REG 0x02 +#define ATAO_CFG2_CALLD_NOP (0 << 14) +#define ATAO_CFG2_CALLD(x) ((((x) >> 3) + 1) << 14) +#define ATAO_CFG2_FFRTEN (1 << 13) +#define ATAO_CFG2_DACS(x) (1 << (((x) / 2) + 8)) +#define ATAO_CFG2_LDAC(x) (1 << (((x) / 2) + 3)) +#define ATAO_CFG2_PROMEN (1 << 2) +#define ATAO_CFG2_SCLK (1 << 1) +#define ATAO_CFG2_SDATA (1 << 0) +#define ATAO_CFG3_REG 0x04 +#define ATAO_CFG3_DMAMODE (1 << 6) +#define ATAO_CFG3_CLKOUT (1 << 5) +#define ATAO_CFG3_RCLKEN (1 << 4) +#define ATAO_CFG3_DOUTEN2 (1 << 3) +#define ATAO_CFG3_DOUTEN1 (1 << 2) +#define ATAO_CFG3_EN2_5V (1 << 1) +#define ATAO_CFG3_SCANEN (1 << 0) +#define ATAO_82C53_BASE 0x06 +#define ATAO_CFG1_REG 0x0a +#define ATAO_CFG1_EXTINT2EN (1 << 15) +#define ATAO_CFG1_EXTINT1EN (1 << 14) +#define ATAO_CFG1_CNTINT2EN (1 << 13) +#define ATAO_CFG1_CNTINT1EN (1 << 12) +#define ATAO_CFG1_TCINTEN (1 << 11) +#define ATAO_CFG1_CNT1SRC (1 << 10) +#define ATAO_CFG1_CNT2SRC (1 << 9) +#define ATAO_CFG1_FIFOEN (1 << 8) +#define ATAO_CFG1_GRP2WR (1 << 7) +#define ATAO_CFG1_EXTUPDEN (1 << 6) +#define ATAO_CFG1_DMARQ (1 << 5) +#define ATAO_CFG1_DMAEN (1 << 4) +#define ATAO_CFG1_CH(x) (((x) & 0xf) << 0) +#define ATAO_STATUS_REG 0x0a +#define ATAO_STATUS_FH (1 << 6) +#define ATAO_STATUS_FE (1 << 5) +#define ATAO_STATUS_FF (1 << 4) +#define ATAO_STATUS_INT2 (1 << 3) +#define ATAO_STATUS_INT1 (1 << 2) +#define ATAO_STATUS_TCINT (1 << 1) +#define ATAO_STATUS_PROMOUT (1 << 0) +#define ATAO_FIFO_WRITE_REG 0x0c +#define ATAO_FIFO_CLEAR_REG 0x0c +#define ATAO_AO_REG(x) (0x0c + ((x) * 2)) -#include "../comedidev.h" - -#include <linux/ioport.h> - -/* board egisters */ /* registers with _2_ are accessed when GRP2WR is set in CFG1 */ +#define ATAO_2_DMATCCLR_REG 0x00 +#define ATAO_2_INT1CLR_REG 0x02 +#define ATAO_2_INT2CLR_REG 0x04 +#define ATAO_2_RTSISHFT_REG 0x06 +#define ATAO_2_RTSISHFT_RSI (1 << 0) +#define ATAO_2_RTSISTRB_REG 0x07 -#define ATAO_SIZE 0x20 - -#define ATAO_2_DMATCCLR 0x00 /* W 16 */ -#define ATAO_DIN 0x00 /* R 16 */ -#define ATAO_DOUT 0x00 /* W 16 */ - -#define ATAO_CFG2 0x02 /* W 16 */ -#define CALLD1 0x8000 -#define CALLD0 0x4000 -#define FFRTEN 0x2000 -#define DAC2S8 0x1000 -#define DAC2S6 0x0800 -#define DAC2S4 0x0400 -#define DAC2S2 0x0200 -#define DAC2S0 0x0100 -#define LDAC8 0x0080 -#define LDAC6 0x0040 -#define LDAC4 0x0020 -#define LDAC2 0x0010 -#define LDAC0 0x0008 -#define PROMEN 0x0004 -#define SCLK 0x0002 -#define SDATA 0x0001 - -#define ATAO_2_INT1CLR 0x02 /* W 16 */ - -#define ATAO_CFG3 0x04 /* W 16 */ -#define DMAMODE 0x0040 -#define CLKOUT 0x0020 -#define RCLKEN 0x0010 -#define DOUTEN2 0x0008 -#define DOUTEN1 0x0004 -#define EN2_5V 0x0002 -#define SCANEN 0x0001 - -#define ATAO_2_INT2CLR 0x04 /* W 16 */ - -#define ATAO_82C53_BASE 0x06 /* RW 8 */ - -#define ATAO_82C53_CNTR1 0x06 /* RW 8 */ -#define ATAO_82C53_CNTR2 0x07 /* RW 8 */ -#define ATAO_82C53_CNTR3 0x08 /* RW 8 */ -#define ATAO_82C53_CNTRCMD 0x09 /* W 8 */ -#define CNTRSEL1 0x80 -#define CNTRSEL0 0x40 -#define RWSEL1 0x20 -#define RWSEL0 0x10 -#define MODESEL2 0x08 -#define MODESEL1 0x04 -#define MODESEL0 0x02 -#define BCDSEL 0x01 - /* read-back command */ -#define COUNT 0x20 -#define STATUS 0x10 -#define CNTR3 0x08 -#define CNTR2 0x04 -#define CNTR1 0x02 - /* status */ -#define OUT 0x80 -#define _NULL 0x40 -#define RW1 0x20 -#define RW0 0x10 -#define MODE2 0x08 -#define MODE1 0x04 -#define MODE0 0x02 -#define BCD 0x01 - -#define ATAO_2_RTSISHFT 0x06 /* W 8 */ -#define RSI 0x01 - -#define ATAO_2_RTSISTRB 0x07 /* W 8 */ - -#define ATAO_CFG1 0x0a /* W 16 */ -#define EXTINT2EN 0x8000 -#define EXTINT1EN 0x4000 -#define CNTINT2EN 0x2000 -#define CNTINT1EN 0x1000 -#define TCINTEN 0x0800 -#define CNT1SRC 0x0400 -#define CNT2SRC 0x0200 -#define FIFOEN 0x0100 -#define GRP2WR 0x0080 -#define EXTUPDEN 0x0040 -#define DMARQ 0x0020 -#define DMAEN 0x0010 -#define CH_mask 0x000f -#define ATAO_STATUS 0x0a /* R 16 */ -#define FH 0x0040 -#define FE 0x0020 -#define FF 0x0010 -#define INT2 0x0008 -#define INT1 0x0004 -#define TCINT 0x0002 -#define PROMOUT 0x0001 - -#define ATAO_FIFO_WRITE 0x0c /* W 16 */ -#define ATAO_FIFO_CLEAR 0x0c /* R 16 */ -#define ATAO_DACn(x) (0x0c + 2*(x)) /* W */ - -/* - * 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. - */ struct atao_board { const char *name; int n_ao_chans; @@ -159,318 +106,304 @@ struct atao_board { static const struct atao_board atao_boards[] = { { - .name = "ai-ao-6", - .n_ao_chans = 6, - }, - { - .name = "ai-ao-10", - .n_ao_chans = 10, - }, + .name = "at-ao-6", + .n_ao_chans = 6, + }, { + .name = "at-ao-10", + .n_ao_chans = 10, + }, }; -#define thisboard ((struct atao_board *)dev->board_ptr) - struct atao_private { - unsigned short cfg1; - unsigned short cfg2; unsigned short cfg3; /* Used for AO readback */ unsigned int ao_readback[10]; -}; -#define devpriv ((struct atao_private *)dev->private) - -static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int atao_detach(struct comedi_device *dev); -static struct comedi_driver driver_atao = { - .driver_name = "ni_at_ao", - .module = THIS_MODULE, - .attach = atao_attach, - .detach = atao_detach, - .board_name = &atao_boards[0].name, - .offset = sizeof(struct atao_board), - .num_names = ARRAY_SIZE(atao_boards), + /* Used for caldac readback */ + unsigned char caldac[21]; }; -static int __init driver_atao_init_module(void) +static void atao_select_reg_group(struct comedi_device *dev, int group) { - return comedi_driver_register(&driver_atao); -} + struct atao_private *devpriv = dev->private; -static void __exit driver_atao_cleanup_module(void) -{ - comedi_driver_unregister(&driver_atao); + if (group) + devpriv->cfg1 |= ATAO_CFG1_GRP2WR; + else + devpriv->cfg1 &= ~ATAO_CFG1_GRP2WR; + outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG); } -module_init(driver_atao_init_module); -module_exit(driver_atao_cleanup_module); - -static void atao_reset(struct comedi_device *dev); - -static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_dio_insn_bits(struct comedi_device *dev, +static int atao_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_calib_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int atao_calib_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) + struct comedi_insn *insn, + unsigned int *data) { - struct comedi_subdevice *s; - unsigned long iobase; - int ao_unipolar; + struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - iobase = it->options[0]; - if (iobase == 0) - iobase = 0x1c0; - ao_unipolar = it->options[3]; + if (chan == 0) + atao_select_reg_group(dev, 1); - printk(KERN_INFO "comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase); + for (i = 0; i < insn->n; i++) { + val = data[i]; + devpriv->ao_readback[chan] = val; - if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) { - printk(" I/O port conflict\n"); - return -EIO; + /* munge offset binary (unsigned) to two's complement */ + val = comedi_offset_munge(s, val); + outw(val, dev->iobase + ATAO_AO_REG(chan)); } - dev->iobase = iobase; - - /* dev->board_ptr = atao_probe(dev); */ - - dev->board_name = thisboard->name; - if (alloc_private(dev, sizeof(struct atao_private)) < 0) - return -ENOMEM; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; + if (chan == 0) + atao_select_reg_group(dev, 0); - s = dev->subdevices + 0; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->n_ao_chans; - s->maxdata = (1 << 12) - 1; - if (ao_unipolar) - s->range_table = &range_unipolar10; - else - s->range_table = &range_bipolar10; - s->insn_write = &atao_ao_winsn; - s->insn_read = &atao_ao_rinsn; - - s = dev->subdevices + 1; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = atao_dio_insn_bits; - s->insn_config = atao_dio_insn_config; - - s = dev->subdevices + 2; - /* caldac subdevice */ - s->type = COMEDI_SUBD_CALIB; - s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; - s->n_chan = 21; - s->maxdata = 0xff; - s->insn_read = atao_calib_insn_read; - s->insn_write = atao_calib_insn_write; - - s = dev->subdevices + 3; - /* eeprom subdevice */ - /* s->type=COMEDI_SUBD_EEPROM; */ - s->type = COMEDI_SUBD_UNUSED; + return insn->n; +} - atao_reset(dev); +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; - printk(KERN_INFO "\n"); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - return 0; + return insn->n; } -static int atao_detach(struct comedi_device *dev) +static int atao_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - printk(KERN_INFO "comedi%d: atao: remove\n", dev->minor); + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + ATAO_DIO_REG); - if (dev->iobase) - release_region(dev->iobase, ATAO_SIZE); + data[1] = inw(dev->iobase + ATAO_DIO_REG); - return 0; + return insn->n; } -static void atao_reset(struct comedi_device *dev) +static int atao_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* This is the reset sequence described in the manual */ + struct atao_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; - devpriv->cfg1 = 0; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); + if (chan < 4) + mask = 0x0f; + else + mask = 0xf0; - outb(RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); - outb(0x03, dev->iobase + ATAO_82C53_CNTR1); - outb(CNTRSEL0 | RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; - devpriv->cfg2 = 0; - outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); + if (s->io_bits & 0x0f) + devpriv->cfg3 |= ATAO_CFG3_DOUTEN1; + else + devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN1; + if (s->io_bits & 0xf0) + devpriv->cfg3 |= ATAO_CFG3_DOUTEN2; + else + devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN2; - devpriv->cfg3 = 0; - outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); + outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG); - inw(dev->iobase + ATAO_FIFO_CLEAR); + return insn->n; +} - devpriv->cfg1 |= GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); +/* + * There are three DAC8800 TrimDACs on the board. These are 8-channel, + * 8-bit DACs that are used to calibrate the Analog Output channels. + * The factory default calibration values are stored in the EEPROM. + * The TrimDACs, and EEPROM addresses, are mapped as: + * + * Channel EEPROM Description + * ----------------- ------ ----------------------------------- + * 0 - DAC0 Chan 0 0x30 AO Channel 0 Offset + * 1 - DAC0 Chan 1 0x31 AO Channel 0 Gain + * 2 - DAC0 Chan 2 0x32 AO Channel 1 Offset + * 3 - DAC0 Chan 3 0x33 AO Channel 1 Gain + * 4 - DAC0 Chan 4 0x34 AO Channel 2 Offset + * 5 - DAC0 Chan 5 0x35 AO Channel 2 Gain + * 6 - DAC0 Chan 6 0x36 AO Channel 3 Offset + * 7 - DAC0 Chan 7 0x37 AO Channel 3 Gain + * 8 - DAC1 Chan 0 0x38 AO Channel 4 Offset + * 9 - DAC1 Chan 1 0x39 AO Channel 4 Gain + * 10 - DAC1 Chan 2 0x3a AO Channel 5 Offset + * 11 - DAC1 Chan 3 0x3b AO Channel 5 Gain + * 12 - DAC1 Chan 4 0x3c 2.5V Offset + * 13 - DAC1 Chan 5 0x3d AO Channel 6 Offset (at-ao-10 only) + * 14 - DAC1 Chan 6 0x3e AO Channel 6 Gain (at-ao-10 only) + * 15 - DAC1 Chan 7 0x3f AO Channel 7 Offset (at-ao-10 only) + * 16 - DAC2 Chan 0 0x40 AO Channel 7 Gain (at-ao-10 only) + * 17 - DAC2 Chan 1 0x41 AO Channel 8 Offset (at-ao-10 only) + * 18 - DAC2 Chan 2 0x42 AO Channel 8 Gain (at-ao-10 only) + * 19 - DAC2 Chan 3 0x43 AO Channel 9 Offset (at-ao-10 only) + * 20 - DAC2 Chan 4 0x44 AO Channel 9 Gain (at-ao-10 only) + * DAC2 Chan 5 0x45 Reserved + * DAC2 Chan 6 0x46 Reserved + * DAC2 Chan 7 0x47 Reserved + */ +static int atao_calib_insn_write(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); + unsigned int bitstring; + unsigned int val; + int bit; - outw(0, dev->iobase + ATAO_2_INT1CLR); - outw(0, dev->iobase + ATAO_2_INT2CLR); - outw(0, dev->iobase + ATAO_2_DMATCCLR); + if (insn->n == 0) + return 0; - devpriv->cfg1 &= ~GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); -} + devpriv->caldac[chan] = data[insn->n - 1] & s->maxdata; -static int atao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i; - int chan = CR_CHAN(insn->chanspec); - short bits; + /* write the channel and last data value to the caldac */ + bitstring = ((chan & 0x7) << 8) | devpriv->caldac[chan]; - for (i = 0; i < insn->n; i++) { - bits = data[i] - 0x800; - if (chan == 0) { - devpriv->cfg1 |= GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - } - outw(bits, dev->iobase + ATAO_DACn(chan)); - if (chan == 0) { - devpriv->cfg1 &= ~GRP2WR; - outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); - } - devpriv->ao_readback[chan] = data[i]; + /* clock the bitstring to the caldac; MSB -> LSB */ + for (bit = 1 << 10; bit; bit >>= 1) { + val = (bit & bitstring) ? ATAO_CFG2_SDATA : 0; + + outw(val, dev->iobase + ATAO_CFG2_REG); + outw(val | ATAO_CFG2_SCLK, dev->iobase + ATAO_CFG2_REG); } - return i; + /* strobe the caldac to load the value */ + outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG); + outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); + + return insn->n; } -static int atao_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int atao_calib_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; - int chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + data[i] = devpriv->caldac[chan]; - return i; + return insn->n; } -static int atao_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void atao_reset(struct comedi_device *dev) { - if (insn->n != 2) - return -EINVAL; + struct atao_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + ATAO_82C53_BASE; - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outw(s->state, dev->iobase + ATAO_DOUT); - } + /* This is the reset sequence described in the manual */ - data[1] = inw(dev->iobase + ATAO_DIN); + devpriv->cfg1 = 0; + outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG); - return 2; -} + /* Put outputs of counter 1 and counter 2 in a high state */ + i8254_set_mode(timer_base, 0, 0, I8254_MODE4 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE4 | I8254_BINARY); + i8254_write(timer_base, 0, 0, 0x0003); -static int atao_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - unsigned int mask, bit; - - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ - - mask = (chan < 4) ? 0x0f : 0xf0; - bit = (chan < 4) ? DOUTEN1 : DOUTEN2; - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= mask; - devpriv->cfg3 |= bit; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~mask; - devpriv->cfg3 &= ~bit; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } + outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG); - outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); + devpriv->cfg3 = 0; + outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG); - return 1; -} + inw(dev->iobase + ATAO_FIFO_CLEAR_REG); -/* - * Figure 2-1 in the manual shows 3 chips labeled DAC8800, which - * are 8-channel 8-bit DACs. These are most likely the calibration - * DACs. It is not explicitly stated in the manual how to access - * the caldacs, but we can guess. - */ -static int atao_calib_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i; - for (i = 0; i < insn->n; i++) - data[i] = 0; /* XXX */ - return insn->n; + atao_select_reg_group(dev, 1); + outw(0, dev->iobase + ATAO_2_INT1CLR_REG); + outw(0, dev->iobase + ATAO_2_INT2CLR_REG); + outw(0, dev->iobase + ATAO_2_DMATCCLR_REG); + atao_select_reg_group(dev, 0); } -static int atao_calib_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - unsigned int bitstring, bit; - unsigned int chan = CR_CHAN(insn->chanspec); + const struct atao_board *board = comedi_board(dev); + struct atao_private *devpriv; + struct comedi_subdevice *s; + int ret; - bitstring = ((chan & 0x7) << 8) | (data[insn->n - 1] & 0xff); + ret = comedi_request_region(dev, it->options[0], 0x20); + if (ret) + return ret; - for (bit = 1 << (11 - 1); bit; bit >>= 1) { - outw(devpriv->cfg2 | ((bit & bitstring) ? SDATA : 0), - dev->iobase + ATAO_CFG2); - outw(devpriv->cfg2 | SCLK | ((bit & bitstring) ? SDATA : 0), - dev->iobase + ATAO_CFG2); - } - /* strobe the appropriate caldac */ - outw(devpriv->cfg2 | (((chan >> 3) + 1) << 14), - dev->iobase + ATAO_CFG2); - outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - return insn->n; + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + /* Analog Output subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_ao_chans; + 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; + + /* Digital I/O subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = atao_dio_insn_bits; + s->insn_config = atao_dio_insn_config; + + /* caldac subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_CALIB; + s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; + s->n_chan = (board->n_ao_chans * 2) + 1; + s->maxdata = 0xff; + s->insn_read = atao_calib_insn_read; + s->insn_write = atao_calib_insn_write; + + /* EEPROM subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_UNUSED; + + atao_reset(dev); + + return 0; } +static struct comedi_driver ni_at_ao_driver = { + .driver_name = "ni_at_ao", + .module = THIS_MODULE, + .attach = atao_attach, + .detach = comedi_legacy_detach, + .board_name = &atao_boards[0].name, + .offset = sizeof(struct atao_board), + .num_names = ARRAY_SIZE(atao_boards), +}; +module_comedi_driver(ni_at_ao_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for NI AT-AO-6/10 boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c index 3330b3d53e8..d03935257b9 100644 --- a/drivers/staging/comedi/drivers/ni_atmio.c +++ b/drivers/staging/comedi/drivers/ni_atmio.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: ni_atmio @@ -93,17 +89,15 @@ are not supported. */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/delay.h> #include <linux/isapnp.h> #include "ni_stc.h" #include "8255.h" -#undef DEBUG - #define ATMIO 1 #undef PCIMIO @@ -268,8 +262,9 @@ static const struct ni_board_struct ni_boards[] = { } }; -static const int ni_irqpin[] = - { -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7 }; +static const int ni_irqpin[] = { + -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7 +}; #define interrupt_pin(a) (ni_irqpin[(a)]) @@ -279,8 +274,9 @@ static const int ni_irqpin[] = struct ni_private { struct pnp_dev *isapnp_dev; - NI_PRIVATE_COMMON}; -#define devpriv ((struct ni_private *)dev->private) + NI_PRIVATE_COMMON + +}; /* How we access registers */ @@ -299,6 +295,7 @@ struct ni_private { static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->window_lock, flags); @@ -313,6 +310,7 @@ static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr) static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr) { + struct ni_private *devpriv = dev->private; unsigned long flags; uint16_t ret; @@ -339,55 +337,14 @@ static struct pnp_device_id device_ids[] = { MODULE_DEVICE_TABLE(pnp, device_ids); -static int ni_atmio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int ni_atmio_detach(struct comedi_device *dev); -static struct comedi_driver driver_atmio = { - .driver_name = "ni_atmio", - .module = THIS_MODULE, - .attach = ni_atmio_attach, - .detach = ni_atmio_detach, -}; - -static int __init driver_atmio_init_module(void) -{ - return comedi_driver_register(&driver_atmio); -} - -static void __exit driver_atmio_cleanup_module(void) -{ - comedi_driver_unregister(&driver_atmio); -} - -module_init(driver_atmio_init_module); -module_exit(driver_atmio_cleanup_module); - #include "ni_mio_common.c" -static int ni_getboardtype(struct comedi_device *dev); - -/* clean up allocated resources */ -static int ni_atmio_detach(struct comedi_device *dev) -{ - mio_common_detach(dev); - - if (dev->iobase) - release_region(dev->iobase, NI_SIZE); - if (dev->irq) - free_irq(dev->irq, dev); - - if (devpriv->isapnp_dev) - pnp_device_detach(devpriv->isapnp_dev); - - return 0; -} - static int ni_isapnp_find_board(struct pnp_dev **dev) { struct pnp_dev *isapnp_dev = NULL; int i; - for (i = 0; i < n_ni_boards; i++) { + for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { isapnp_dev = pnp_find_dev(NULL, ISAPNP_VENDOR('N', 'I', 'C'), ISAPNP_FUNCTION(ni_boards[i]. @@ -414,25 +371,47 @@ static int ni_isapnp_find_board(struct pnp_dev **dev) } break; } - if (i == n_ni_boards) + if (i == ARRAY_SIZE(ni_boards)) return -ENODEV; *dev = isapnp_dev; return 0; } +static int ni_getboardtype(struct comedi_device *dev) +{ + int device_id = ni_read_eeprom(dev, 511); + int i; + + for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { + if (ni_boards[i].device_id == device_id) + return i; + + } + if (device_id == 255) + printk(" can't find board\n"); + else if (device_id == 0) + printk(" EEPROM read error (?) or device not found\n"); + else + printk(" unknown device ID %d -- contact author\n", device_id); + + return -1; +} + static int ni_atmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct ni_board_struct *boardtype; + struct ni_private *devpriv; struct pnp_dev *isapnp_dev; int ret; unsigned long iobase; int board; unsigned int irq; - /* allocate private area */ ret = ni_alloc_private(dev); - if (ret < 0) + if (ret) return ret; + devpriv = dev->private; devpriv->stc_writew = &ni_atmio_win_out; devpriv->stc_readw = &ni_atmio_win_in; @@ -452,28 +431,9 @@ static int ni_atmio_attach(struct comedi_device *dev, devpriv->isapnp_dev = isapnp_dev; } - /* reserve our I/O region */ - - printk("comedi%d: ni_atmio: 0x%04lx", dev->minor, iobase); - if (!request_region(iobase, NI_SIZE, "ni_atmio")) { - printk(" I/O port conflict\n"); - return -EIO; - } - - dev->iobase = iobase; - -#ifdef DEBUG - /* board existence sanity check */ - { - int i; - - printk(" board fingerprint:"); - for (i = 0; i < 16; i += 2) { - printk(" %04x %02x", inw(dev->iobase + i), - inb(dev->iobase + i + 1)); - } - } -#endif + ret = comedi_request_region(dev, iobase, NI_SIZE); + if (ret) + return ret; /* get board type */ @@ -482,9 +442,10 @@ static int ni_atmio_attach(struct comedi_device *dev, return -EIO; dev->board_ptr = ni_boards + board; + boardtype = comedi_board(dev); - printk(" %s", boardtype.name); - dev->board_name = boardtype.name; + printk(" %s", boardtype->name); + dev->board_name = boardtype->name; /* irq stuff */ @@ -506,7 +467,7 @@ static int ni_atmio_attach(struct comedi_device *dev, /* generic E series stuff in ni_mio_common.c */ - ret = ni_E_init(dev, it); + ret = ni_E_init(dev); if (ret < 0) return ret; @@ -514,22 +475,20 @@ static int ni_atmio_attach(struct comedi_device *dev, return 0; } -static int ni_getboardtype(struct comedi_device *dev) +static void ni_atmio_detach(struct comedi_device *dev) { - int device_id = ni_read_eeprom(dev, 511); - int i; - - for (i = 0; i < n_ni_boards; i++) { - if (ni_boards[i].device_id == device_id) - return i; - - } - if (device_id == 255) - printk(" can't find board\n"); - else if (device_id == 0) - printk(" EEPROM read error (?) or device not found\n"); - else - printk(" unknown device ID %d -- contact author\n", device_id); + struct ni_private *devpriv = dev->private; - return -1; + mio_common_detach(dev); + comedi_legacy_detach(dev); + if (devpriv->isapnp_dev) + pnp_device_detach(devpriv->isapnp_dev); } + +static struct comedi_driver ni_atmio_driver = { + .driver_name = "ni_atmio", + .module = THIS_MODULE, + .attach = ni_atmio_attach, + .detach = ni_atmio_detach, +}; +module_comedi_driver(ni_atmio_driver); diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index 285b933551a..6ad27f50c6e 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -12,11 +12,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_atmio16d @@ -35,11 +30,11 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) * */ +#include <linux/module.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> - +#include "comedi_fc.h" #include "8255.h" /* Configuration and Status Registers */ @@ -101,8 +96,6 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) #define CLOCK_100_HZ 0x8F25 /* Other miscellaneous defines */ #define ATMIO16D_SIZE 32 /* bus address range */ -#define devpriv ((struct atmio16d_private *)dev->private) -#define ATMIO16D_TIMEOUT 10 struct atmio16_board_t { @@ -110,95 +103,32 @@ struct atmio16_board_t { int has_8255; }; -static const struct atmio16_board_t atmio16_boards[] = { - { - .name = "atmio16", - .has_8255 = 0, - }, - { - .name = "atmio16d", - .has_8255 = 1, - }, -}; - -#define n_atmio16_boards ARRAY_SIZE(atmio16_boards) - -#define boardtype ((const struct atmio16_board_t *)dev->board_ptr) - -/* function prototypes */ -static int atmio16d_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int atmio16d_detach(struct comedi_device *dev); -static irqreturn_t atmio16d_interrupt(int irq, void *d); -static int atmio16d_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int atmio16d_ai_cmd(struct comedi_device *dev, - struct comedi_subdevice *s); -static int atmio16d_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void reset_counters(struct comedi_device *dev); -static void reset_atmio16d(struct comedi_device *dev); - -/* main driver struct */ -static struct comedi_driver driver_atmio16d = { - .driver_name = "atmio16", - .module = THIS_MODULE, - .attach = atmio16d_attach, - .detach = atmio16d_detach, - .board_name = &atmio16_boards[0].name, - .num_names = n_atmio16_boards, - .offset = sizeof(struct atmio16_board_t), -}; - -static int __init driver_atmio16d_init_module(void) -{ - return comedi_driver_register(&driver_atmio16d); -} - -static void __exit driver_atmio16d_cleanup_module(void) -{ - comedi_driver_unregister(&driver_atmio16d); -} - -module_init(driver_atmio16d_init_module); -module_exit(driver_atmio16d_cleanup_module); - /* range structs */ -static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, { - BIP_RANGE - (10), - BIP_RANGE - (1), - BIP_RANGE - (0.1), - BIP_RANGE - (0.02) - } +static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { + 4, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02) + } }; -static const struct comedi_lrange range_atmio16d_ai_5_bipolar = { 4, { - BIP_RANGE - (5), - BIP_RANGE - (0.5), - BIP_RANGE - (0.05), - BIP_RANGE - (0.01) - } +static const struct comedi_lrange range_atmio16d_ai_5_bipolar = { + 4, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_atmio16d_ai_unipolar = { 4, { - UNI_RANGE - (10), - UNI_RANGE - (1), - UNI_RANGE - (0.1), - UNI_RANGE - (0.02) - } +static const struct comedi_lrange range_atmio16d_ai_unipolar = { + 4, { + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) + } }; /* private data struct */ @@ -255,6 +185,7 @@ static void reset_counters(struct comedi_device *dev) static void reset_atmio16d(struct comedi_device *dev) { + struct atmio16d_private *devpriv = dev->private; int i; /* now we need to initialize the board */ @@ -288,13 +219,9 @@ static void reset_atmio16d(struct comedi_device *dev) static irqreturn_t atmio16d_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - -#ifdef DEBUG1 - printk(KERN_DEBUG "atmio16d_interrupt!\n"); -#endif + struct comedi_subdevice *s = dev->read_subdev; - comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG)); + comedi_buf_put(s, inw(dev->iobase + AD_FIFO_REG)); comedi_event(dev, s); return IRQ_HANDLED; @@ -304,96 +231,56 @@ static int atmio16d_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp; -#ifdef DEBUG1 - printk(KERN_DEBUG "atmio16d_ai_cmdtest\n"); -#endif - /* make sure triggers are valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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_FOLLOW | TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + 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 2: make sure trigger sources are unique & mutually compatible */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* 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->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } if (cmd->scan_begin_src == TRIG_FOLLOW) { /* internal trigger */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); } else { #if 0 /* external trigger */ /* should be level/edge, hi/lo specification here */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); #endif } - if (cmd->convert_arg < 10000) { - cmd->convert_arg = 10000; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); #if 0 - if (cmd->convert_arg > SLOWEST_TIMER) { - cmd->convert_arg = SLOWEST_TIMER; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER); #endif - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + + 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_arg != 0) { - cmd->stop_arg = 0; - err++; - } + } else { /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -405,13 +292,12 @@ static int atmio16d_ai_cmdtest(struct comedi_device *dev, static int atmio16d_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct atmio16d_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int timer, base_clock; unsigned int sample_count, tmp, chan, gain; int i; -#ifdef DEBUG1 - printk(KERN_DEBUG "atmio16d_ai_cmd\n"); -#endif + /* This is slowly becoming a working command interface. * * It is still uber-experimental */ @@ -561,19 +447,33 @@ static int atmio16d_ai_cancel(struct comedi_device *dev, return 0; } -/* Mode 0 is used to get a single conversion on demand */ +static int atmio16d_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + STAT_REG); + if (status & STAT_AD_CONVAVAIL) + return 0; + if (status & STAT_AD_OVERFLOW) { + outw(0, dev->iobase + AD_CLEAR_REG); + return -EOVERFLOW; + } + return -EBUSY; +} + static int atmio16d_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i, t; + struct atmio16d_private *devpriv = dev->private; + int i; int chan; int gain; - int status; + int ret; -#ifdef DEBUG1 - printk(KERN_DEBUG "atmio16d_ai_insn_read\n"); -#endif chan = CR_CHAN(insn->chanspec); gain = CR_RANGE(insn->chanspec); @@ -588,34 +488,17 @@ static int atmio16d_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { /* start the conversion */ outw(0, dev->iobase + START_CONVERT_REG); + /* wait for it to finish */ - for (t = 0; t < ATMIO16D_TIMEOUT; t++) { - /* check conversion status */ - status = inw(dev->iobase + STAT_REG); -#ifdef DEBUG1 - printk(KERN_DEBUG "status=%x\n", status); -#endif - if (status & STAT_AD_CONVAVAIL) { - /* read the data now */ - data[i] = inw(dev->iobase + AD_FIFO_REG); - /* change to two's complement if need be */ - if (devpriv->adc_coding == adc_2comp) - data[i] ^= 0x800; - break; - } - if (status & STAT_AD_OVERFLOW) { - printk(KERN_INFO "atmio16d: a/d FIFO overflow\n"); - outw(0, dev->iobase + AD_CLEAR_REG); - - return -ETIME; - } - } - /* end waiting, now check if it timed out */ - if (t == ATMIO16D_TIMEOUT) { - printk(KERN_INFO "atmio16d: timeout\n"); + ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0); + if (ret) + return ret; - return -ETIME; - } + /* read the data now */ + data[i] = inw(dev->iobase + AD_FIFO_REG); + /* change to two's complement if need be */ + if (devpriv->adc_coding == adc_2comp) + data[i] ^= 0x800; } return i; @@ -625,10 +508,8 @@ 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; -#ifdef DEBUG1 - printk(KERN_DEBUG "atmio16d_ao_insn_read\n"); -#endif for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; @@ -639,12 +520,10 @@ static int atmio16d_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct atmio16d_private *devpriv = dev->private; int i; int chan; int d; -#ifdef DEBUG1 - printk(KERN_DEBUG "atmio16d_ao_insn_write\n"); -#endif chan = CR_CHAN(insn->chanspec); @@ -671,19 +550,15 @@ static int atmio16d_ao_insn_write(struct comedi_device *dev, static int atmio16d_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] | data[1]); + if (comedi_dio_update_state(s, data)) outw(s->state, dev->iobase + MIO_16_DIG_OUT_REG); - } + data[1] = inw(dev->iobase + MIO_16_DIG_IN_REG); - return 2; + return insn->n; } static int atmio16d_dio_insn_config(struct comedi_device *dev, @@ -691,15 +566,20 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int i; - int mask; + struct atmio16d_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 4) + mask = 0x0f; + else + mask = 0xf0; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; - for (i = 0; i < insn->n; i++) { - mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0; - s->io_bits &= ~mask; - if (data[i]) - s->io_bits |= mask; - } devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0 | COMREG2_DOUTEN1); if (s->io_bits & 0x0f) devpriv->com_reg_2_state |= COMREG2_DOUTEN0; @@ -707,7 +587,7 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev, devpriv->com_reg_2_state |= COMREG2_DOUTEN1; outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2); - return i; + return insn->n; } /* @@ -745,48 +625,31 @@ static int atmio16d_dio_insn_config(struct comedi_device *dev, static int atmio16d_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - unsigned int irq; - unsigned long iobase; - int ret; - + const struct atmio16_board_t *board = comedi_board(dev); + struct atmio16d_private *devpriv; struct comedi_subdevice *s; + int ret; - /* make sure the address range is free and allocate it */ - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: atmio16d: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, ATMIO16D_SIZE, "ni_atmio16d")) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - /* board name */ - dev->board_name = boardtype->name; - - ret = alloc_subdevices(dev, 4); - if (ret < 0) + ret = comedi_request_region(dev, it->options[0], ATMIO16D_SIZE); + if (ret) return ret; - ret = alloc_private(dev, sizeof(struct atmio16d_private)); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + /* reset the atmio16d hardware */ reset_atmio16d(dev); - /* check if our interrupt is available and get it */ - irq = it->options[1]; - if (irq) { - - ret = request_irq(irq, atmio16d_interrupt, 0, "atmio16d", dev); - if (ret < 0) { - printk(KERN_INFO "failed to allocate irq %u\n", irq); - return ret; - } - dev->irq = irq; - printk(KERN_INFO "( irq = %u )\n", irq); - } else { - printk(KERN_INFO "( no irq )"); + if (it->options[1]) { + ret = request_irq(it->options[1], atmio16d_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } /* set device options */ @@ -801,17 +664,12 @@ static int atmio16d_attach(struct comedi_device *dev, devpriv->dac1_coding = it->options[12]; /* setup sub-devices */ - s = dev->subdevices + 0; - dev->read_subdev = s; + s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = (devpriv->adc_mux ? 16 : 8); - s->len_chanlist = 16; s->insn_read = atmio16d_ai_insn_read; - s->do_cmdtest = atmio16d_ai_cmdtest; - s->do_cmd = atmio16d_ai_cmd; - s->cancel = atmio16d_ai_cancel; s->maxdata = 0xfff; /* 4095 decimal */ switch (devpriv->adc_range) { case adc_bipolar10: @@ -824,9 +682,17 @@ static int atmio16d_attach(struct comedi_device *dev, s->range_table = &range_atmio16d_ai_unipolar; break; } + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 16; + s->do_cmdtest = atmio16d_ai_cmdtest; + s->do_cmd = atmio16d_ai_cmd; + s->cancel = atmio16d_ai_cancel; + } /* ao subdevice */ - s++; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; @@ -852,7 +718,7 @@ static int atmio16d_attach(struct comedi_device *dev, } /* Digital I/O */ - s++; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 8; @@ -862,42 +728,53 @@ static int atmio16d_attach(struct comedi_device *dev, s->range_table = &range_digital; /* 8255 subdevice */ - s++; - if (boardtype->has_8255) - subdev_8255_init(dev, s, NULL, dev->iobase); - else + s = &dev->subdevices[3]; + if (board->has_8255) { + ret = subdev_8255_init(dev, s, NULL, dev->iobase); + if (ret) + return ret; + } else { s->type = COMEDI_SUBD_UNUSED; + } /* don't yet know how to deal with counter/timers */ #if 0 - s++; + s = &dev->subdevices[4]; /* do */ s->type = COMEDI_SUBD_TIMER; s->n_chan = 0; s->maxdata = 0 #endif - printk("\n"); return 0; } -static int atmio16d_detach(struct comedi_device *dev) +static void atmio16d_detach(struct comedi_device *dev) { - printk(KERN_INFO "comedi%d: atmio16d: remove\n", dev->minor); - - if (dev->subdevices && boardtype->has_8255) - subdev_8255_cleanup(dev, dev->subdevices + 3); - - if (dev->irq) - free_irq(dev->irq, dev); - reset_atmio16d(dev); + comedi_legacy_detach(dev); +} - if (dev->iobase) - release_region(dev->iobase, ATMIO16D_SIZE); +static const struct atmio16_board_t atmio16_boards[] = { + { + .name = "atmio16", + .has_8255 = 0, + }, { + .name = "atmio16d", + .has_8255 = 1, + }, +}; - return 0; -} +static struct comedi_driver atmio16d_driver = { + .driver_name = "atmio16", + .module = THIS_MODULE, + .attach = atmio16d_attach, + .detach = atmio16d_detach, + .board_name = &atmio16_boards[0].name, + .num_names = ARRAY_SIZE(atmio16_boards), + .offset = sizeof(struct atmio16_board_t), +}; +module_comedi_driver(atmio16d_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 2672629e9ff..728bf7f14f7 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -1,6 +1,6 @@ /* * comedi/drivers/ni_daq_700.c - * Driver for DAQCard-700 DIO only + * Driver for DAQCard-700 DIO/AI * copied from 8255 * * COMEDI - Linux Control and Measurement Device Interface @@ -15,11 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * */ /* @@ -29,577 +24,244 @@ Author: Fred Brooks <nsaspook@nsaspook.com>, based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@able.es> Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700) Status: works -Updated: Thu, 21 Feb 2008 12:07:20 +0000 +Updated: Wed, 19 Sep 2012 12:07:20 +0000 + +The daqcard-700 appears in Comedi as a digital I/O subdevice (0) with +16 channels and a analog input subdevice (1) with 16 single-ended channels. -The daqcard-700 appears in Comedi as a single digital I/O subdevice with -16 channels. The channel 0 corresponds to the daqcard-700's output +Digital: The channel 0 corresponds to the daqcard-700's output port, bit 0; channel 8 corresponds to the input port, bit 0. -Direction configuration: channels 0-7 output, 8-15 input (8225 device +Digital direction configuration: channels 0-7 output, 8-15 input (8225 device emu as port A output, port B input, port C N/A). +Analog: The input range is 0 to 4095 for -10 to +10 volts IRQ is assigned but not used. + +Version 0.1 Original DIO only driver +Version 0.2 DIO and basic AI analog input support on 16 se channels + +Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf + User Manual: http://www.ni.com/pdf/manuals/320676d.pdf */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> -#include <linux/slab.h> -#include "../comedidev.h" -#include <linux/ioport.h> +#include "../comedidev.h" #include <pcmcia/cistpl.h> -#include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -static struct pcmcia_device *pcmcia_cur_dev = NULL; - -#define DIO700_SIZE 8 /* size of io region used by board */ - -static int dio700_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int dio700_detach(struct comedi_device *dev); - -enum dio700_bustype { pcmcia_bustype }; - -struct dio700_board { - const char *name; - int device_id; /* device id for pcmcia board */ - enum dio700_bustype bustype; /* PCMCIA */ - int have_dio; /* have daqcard-700 dio */ - /* function pointers so we can use inb/outb or readb/writeb */ - /* as appropriate */ - unsigned int (*read_byte) (unsigned int address); - void (*write_byte) (unsigned int byte, unsigned int address); -}; - -static const struct dio700_board dio700_boards[] = { - { - .name = "daqcard-700", - /* 0x10b is manufacturer id, 0x4743 is device id */ - .device_id = 0x4743, - .bustype = pcmcia_bustype, - .have_dio = 1, - }, - { - .name = "ni_daq_700", - /* 0x10b is manufacturer id, 0x4743 is device id */ - .device_id = 0x4743, - .bustype = pcmcia_bustype, - .have_dio = 1, - }, -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct dio700_board *)dev->board_ptr) - -struct dio700_private { - - int data; /* number of data points left to be taken */ -}; - -#define devpriv ((struct dio700_private *)dev->private) - -static struct comedi_driver driver_dio700 = { - .driver_name = "ni_daq_700", - .module = THIS_MODULE, - .attach = dio700_attach, - .detach = dio700_detach, - .num_names = ARRAY_SIZE(dio700_boards), - .board_name = &dio700_boards[0].name, - .offset = sizeof(struct dio700_board), -}; - -/* the real driver routines */ - -#define _700_SIZE 8 - -#define _700_DATA 0 - -#define DIO_W 0x04 -#define DIO_R 0x05 - -struct subdev_700_struct { - unsigned long cb_arg; - int (*cb_func) (int, int, int, unsigned long); - int have_irq; -}; - -#define CALLBACK_ARG (((struct subdev_700_struct *)s->private)->cb_arg) -#define CALLBACK_FUNC (((struct subdev_700_struct *)s->private)->cb_func) -#define subdevpriv ((struct subdev_700_struct *)s->private) - -static void do_config(struct comedi_device *dev, struct comedi_subdevice *s); - -void subdev_700_interrupt(struct comedi_device *dev, struct comedi_subdevice *s) +/* daqcard700 registers */ +#define DIO_W 0x04 /* WO 8bit */ +#define DIO_R 0x05 /* RO 8bit */ +#define CMD_R1 0x00 /* WO 8bit */ +#define CMD_R2 0x07 /* RW 8bit */ +#define CMD_R3 0x05 /* W0 8bit */ +#define STA_R1 0x00 /* RO 8bit */ +#define STA_R2 0x01 /* RO 8bit */ +#define ADFIFO_R 0x02 /* RO 16bit */ +#define ADCLEAR_R 0x01 /* WO 8bit */ +#define CDA_R0 0x08 /* RW 8bit */ +#define CDA_R1 0x09 /* RW 8bit */ +#define CDA_R2 0x0A /* RW 8bit */ +#define CMO_R 0x0B /* RO 8bit */ +#define TIC_R 0x06 /* WO 8bit */ + +static int daq700_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - short d; - - d = CALLBACK_FUNC(0, _700_DATA, 0, CALLBACK_ARG); - - comedi_buf_put(s->async, d); - s->async->events |= COMEDI_CB_EOS; - - comedi_event(dev, s); -} -EXPORT_SYMBOL(subdev_700_interrupt); + unsigned int mask; + unsigned int val; -static int subdev_700_cb(int dir, int port, int data, unsigned long arg) -{ - /* port is always A for output and B for input (8255 emu) */ - unsigned long iobase = arg; - - if (dir) { - outb(data, iobase + DIO_W); - return 0; - } else { - return inb(iobase + DIO_R); + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0xff) + outb(s->state & 0xff, dev->iobase + DIO_W); } -} -static int subdev_700_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + val = s->state & 0xff; + val |= inb(dev->iobase + DIO_R) << 8; - if (data[0] & 0xff) - CALLBACK_FUNC(1, _700_DATA, s->state & 0xff, - CALLBACK_ARG); - } + data[1] = val; - data[1] = s->state & 0xff; - data[1] |= CALLBACK_FUNC(0, _700_DATA, 0, CALLBACK_ARG) << 8; - - return 2; + return insn->n; } -static int subdev_700_insn_config(struct comedi_device *dev, +static int daq700_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + int ret; - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - break; - case INSN_CONFIG_DIO_OUTPUT: - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - return 1; -} + /* The DIO channels are not configurable, fix the io_bits */ + s->io_bits = 0x00ff; -static void do_config(struct comedi_device *dev, struct comedi_subdevice *s) -{ /* use powerup defaults */ - return; + return insn->n; } -static int subdev_700_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int daq700_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - int err = 0; - unsigned int tmp; - - /* step 1 */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) - return 1; - - /* step 2 */ - - if (err) - return 2; - - /* step 3 */ - - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->scan_end_arg != 1) { - cmd->scan_end_arg = 1; - err++; - } - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - - if (err) - return 3; - - /* step 4 */ - - if (err) - return 4; - - return 0; + unsigned int status; + + status = inb(dev->iobase + STA_R2); + if ((status & 0x03)) + return -EOVERFLOW; + status = inb(dev->iobase + STA_R1); + if ((status & 0x02)) + return -ENODATA; + if ((status & 0x11) == 0x01) + return 0; + return -EBUSY; } -static int subdev_700_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static int daq700_ai_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - /* FIXME */ + int n, chan; + int d; + int ret; - return 0; + chan = CR_CHAN(insn->chanspec); + /* write channel to multiplexer */ + /* set mask scan bit high to disable scanning */ + outb(chan | 0x80, dev->iobase + CMD_R1); + /* mux needs 2us to really settle [Fred Brooks]. */ + udelay(2); + + /* convert n samples */ + for (n = 0; n < insn->n; n++) { + /* trigger conversion with out0 L to H */ + outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */ + outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */ + /* mode 1 out0 H, L to H, start conversion */ + outb(0x32, dev->iobase + CMO_R); + + /* wait for conversion to end */ + ret = comedi_timeout(dev, s, insn, daq700_ai_eoc, 0); + if (ret) + return ret; + + /* read data */ + d = inw(dev->iobase + ADFIFO_R); + /* mangle the data as necessary */ + /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */ + d &= 0x0fff; + d ^= 0x0800; + data[n] = d; + } + return n; } -static int subdev_700_cancel(struct comedi_device *dev, +/* + * Data acquisition is enabled. + * The counter 0 output is high. + * The I/O connector pin CLK1 drives counter 1 source. + * Multiple-channel scanning is disabled. + * All interrupts are disabled. + * The analog input range is set to +-10 V + * The analog input mode is single-ended. + * The analog input circuitry is initialized to channel 0. + * The A/D FIFO is cleared. + */ +static void daq700_ai_config(struct comedi_device *dev, struct comedi_subdevice *s) { - /* FIXME */ - - return 0; + unsigned long iobase = dev->iobase; + + outb(0x80, iobase + CMD_R1); /* disable scanning, ADC to chan 0 */ + outb(0x00, iobase + CMD_R2); /* clear all bits */ + outb(0x00, iobase + CMD_R3); /* set +-10 range */ + outb(0x32, iobase + CMO_R); /* config counter mode1, out0 to H */ + outb(0x00, iobase + TIC_R); /* clear counter interrupt */ + outb(0x00, iobase + ADCLEAR_R); /* clear the ADC FIFO */ + inw(iobase + ADFIFO_R); /* read 16bit junk from FIFO to clear */ } -int subdev_700_init(struct comedi_device *dev, struct comedi_subdevice *s, - int (*cb) (int, int, int, unsigned long), unsigned long arg) -{ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 16; - s->range_table = &range_digital; - s->maxdata = 1; - - s->private = kmalloc(sizeof(struct subdev_700_struct), GFP_KERNEL); - if (!s->private) - return -ENOMEM; - - CALLBACK_ARG = arg; - if (cb == NULL) - CALLBACK_FUNC = subdev_700_cb; - else - CALLBACK_FUNC = cb; - - s->insn_bits = subdev_700_insn; - s->insn_config = subdev_700_insn_config; - - s->state = 0; - s->io_bits = 0x00ff; - do_config(dev, s); - - return 0; -} -EXPORT_SYMBOL(subdev_700_init); - -int subdev_700_init_irq(struct comedi_device *dev, struct comedi_subdevice *s, - int (*cb) (int, int, int, unsigned long), - unsigned long arg) +static int daq700_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + struct comedi_subdevice *s; int ret; - ret = subdev_700_init(dev, s, cb, arg); - if (ret < 0) + link->config_flags |= CONF_AUTO_SET_IO; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) return ret; + dev->iobase = link->resource[0]->start; - s->do_cmdtest = subdev_700_cmdtest; - s->do_cmd = subdev_700_cmd; - s->cancel = subdev_700_cancel; - - subdevpriv->have_irq = 1; - - return 0; -} -EXPORT_SYMBOL(subdev_700_init_irq); - -void subdev_700_cleanup(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s->private) - if (subdevpriv->have_irq) - - kfree(s->private); -} -EXPORT_SYMBOL(subdev_700_cleanup); - -static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase = 0; -#ifdef incomplete - unsigned int irq = 0; -#endif - struct pcmcia_device *link; - - /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(struct dio700_private)) < 0) - return -ENOMEM; - - /* get base address, irq etc. based on bustype */ - switch (thisboard->bustype) { - case pcmcia_bustype: - link = pcmcia_cur_dev; /* XXX hack */ - if (!link) - return -EIO; - iobase = link->resource[0]->start; -#ifdef incomplete - irq = link->irq; -#endif - break; - default: - printk("bug! couldn't determine board type\n"); - return -EINVAL; - break; - } - printk("comedi%d: ni_daq_700: %s, io 0x%lx", dev->minor, - thisboard->name, iobase); -#ifdef incomplete - if (irq) - printk(", irq %u", irq); - -#endif - - printk("\n"); - - if (iobase == 0) { - printk("io base address is zero!\n"); - return -EINVAL; - } - - dev->iobase = iobase; - -#ifdef incomplete - /* grab our IRQ */ - dev->irq = irq; -#endif - - dev->board_name = thisboard->name; - - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; /* DAQCard-700 dio */ - s = dev->subdevices + 0; - subdev_700_init(dev, s, NULL, dev->iobase); - - return 0; -}; - -static int dio700_detach(struct comedi_device *dev) -{ - printk("comedi%d: ni_daq_700: cs-remove\n", dev->minor); - - if (dev->subdevices) - subdev_700_cleanup(dev, dev->subdevices + 0); - - if (thisboard->bustype != pcmcia_bustype && dev->iobase) - release_region(dev->iobase, DIO700_SIZE); - if (dev->irq) - free_irq(dev->irq, dev); + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 16; + s->range_table = &range_digital; + s->maxdata = 1; + s->insn_bits = daq700_dio_insn_bits; + s->insn_config = daq700_dio_insn_config; + s->io_bits = 0x00ff; + + /* DAQCard-700 ai */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AI; + /* we support single-ended (ground) */ + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = (1 << 12) - 1; + s->range_table = &range_bipolar10; + s->insn_read = daq700_ai_rinsn; + daq700_ai_config(dev, s); return 0; -}; - -static void dio700_config(struct pcmcia_device *link); -static void dio700_release(struct pcmcia_device *link); -static int dio700_cs_suspend(struct pcmcia_device *p_dev); -static int dio700_cs_resume(struct pcmcia_device *p_dev); - -static int dio700_cs_attach(struct pcmcia_device *); -static void dio700_cs_detach(struct pcmcia_device *); +} -struct local_info_t { - struct pcmcia_device *link; - int stop; - struct bus_operations *bus; +static struct comedi_driver daq700_driver = { + .driver_name = "ni_daq_700", + .module = THIS_MODULE, + .auto_attach = daq700_auto_attach, + .detach = comedi_pcmcia_disable, }; -static int dio700_cs_attach(struct pcmcia_device *link) +static int daq700_cs_attach(struct pcmcia_device *link) { - struct local_info_t *local; - - printk(KERN_INFO "ni_daq_700: cs-attach\n"); - - dev_dbg(&link->dev, "dio700_cs_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - local->link = link; - link->priv = local; - - pcmcia_cur_dev = link; - - dio700_config(link); - - return 0; -} /* dio700_cs_attach */ - -static void dio700_cs_detach(struct pcmcia_device *link) -{ - - printk(KERN_INFO "ni_daq_700: cs-detach!\n"); - - dev_dbg(&link->dev, "dio700_cs_detach\n"); - - ((struct local_info_t *)link->priv)->stop = 1; - dio700_release(link); - - /* This points to the parent struct local_info_t struct */ - kfree(link->priv); - -} /* dio700_cs_detach */ - -static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); + return comedi_pcmcia_auto_config(link, &daq700_driver); } -static void dio700_config(struct pcmcia_device *link) -{ - int ret; - - printk(KERN_INFO "ni_daq_700: cs-config\n"); - - dev_dbg(&link->dev, "dio700_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | - CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret != 0) - goto failed; - - return; - -failed: - printk(KERN_INFO "ni_daq_700 cs failed"); - dio700_release(link); - -} /* dio700_config */ - -static void dio700_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "dio700_release\n"); - - pcmcia_disable_device(link); -} /* dio700_release */ - -static int dio700_cs_suspend(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - /* Mark the device as stopped, to block IO until later */ - local->stop = 1; - return 0; -} /* dio700_cs_suspend */ - -static int dio700_cs_resume(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - local->stop = 0; - return 0; -} /* dio700_cs_resume */ - -/*====================================================================*/ - -static const struct pcmcia_device_id dio700_cs_ids[] = { - /* N.B. These IDs should match those in dio700_boards */ - PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743), /* daqcard-700 */ +static const struct pcmcia_device_id daq700_cs_ids[] = { + PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743), PCMCIA_DEVICE_NULL }; +MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids); + +static struct pcmcia_driver daq700_cs_driver = { + .name = "ni_daq_700", + .owner = THIS_MODULE, + .id_table = daq700_cs_ids, + .probe = daq700_cs_attach, + .remove = comedi_pcmcia_auto_unconfig, +}; +module_comedi_pcmcia_driver(daq700_driver, daq700_cs_driver); - -MODULE_DEVICE_TABLE(pcmcia, dio700_cs_ids); MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>"); -MODULE_DESCRIPTION("Comedi driver for National Instruments " - "PCMCIA DAQCard-700 DIO"); +MODULE_DESCRIPTION( + "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI"); +MODULE_VERSION("0.2.00"); MODULE_LICENSE("GPL"); - -struct pcmcia_driver dio700_cs_driver = { - .probe = dio700_cs_attach, - .remove = dio700_cs_detach, - .suspend = dio700_cs_suspend, - .resume = dio700_cs_resume, - .id_table = dio700_cs_ids, - .owner = THIS_MODULE, - .name = "ni_daq_700", -}; - -static int __init init_dio700_cs(void) -{ - pcmcia_register_driver(&dio700_cs_driver); - return 0; -} - -static void __exit exit_dio700_cs(void) -{ - pr_debug("ni_daq_700: unloading\n"); - pcmcia_unregister_driver(&dio700_cs_driver); -} - -int __init init_module(void) -{ - int ret; - - ret = init_dio700_cs(); - if (ret < 0) - return ret; - - return comedi_driver_register(&driver_dio700); -} - -void __exit cleanup_module(void) -{ - exit_dio700_cs(); - comedi_driver_unregister(&driver_dio700); -} diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index 49b824c7bd2..925e82c65b2 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -3,8 +3,8 @@ Driver for National Instruments PCMCIA DAQ-Card DIO-24 Copyright (C) 2002 Daniel Vecino Castel <dvecino@able.es> - PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 2001/08/24 12:13:13 - from the pcmcia package. + PCMCIA crap at end of file is adapted from dummy_cs.c 1.31 + 2001/08/24 12:13:13 from the pcmcia package. The initial developer of the pcmcia dummy_cs.c code is David A. Hinds <dahinds@users.sourceforge.net>. Portions created by David A. Hinds are Copyright (C) 1999 David A. Hinds. All Rights Reserved. @@ -18,12 +18,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: ni_daq_dio24 @@ -37,320 +31,69 @@ This is just a wrapper around the 8255.o driver to properly handle the PCMCIA interface. */ - /* #define LABPC_DEBUG *//* enable debugging messages */ -#undef LABPC_DEBUG - -#include <linux/interrupt.h> -#include <linux/slab.h> +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - -#include "8255.h" - #include <pcmcia/cistpl.h> #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -static struct pcmcia_device *pcmcia_cur_dev = NULL; - -#define DIO24_SIZE 4 /* size of io region used by board */ - -static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int dio24_detach(struct comedi_device *dev); - -enum dio24_bustype { pcmcia_bustype }; - -struct dio24_board_struct { - const char *name; - int device_id; /* device id for pcmcia board */ - enum dio24_bustype bustype; /* PCMCIA */ - int have_dio; /* have 8255 chip */ - /* function pointers so we can use inb/outb or readb/writeb as appropriate */ - unsigned int (*read_byte) (unsigned int address); - void (*write_byte) (unsigned int byte, unsigned int address); -}; - -static const struct dio24_board_struct dio24_boards[] = { - { - .name = "daqcard-dio24", - .device_id = 0x475c, /* 0x10b is manufacturer id, 0x475c is device id */ - .bustype = pcmcia_bustype, - .have_dio = 1, - }, - { - .name = "ni_daq_dio24", - .device_id = 0x475c, /* 0x10b is manufacturer id, 0x475c is device id */ - .bustype = pcmcia_bustype, - .have_dio = 1, - }, -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct dio24_board_struct *)dev->board_ptr) - -struct dio24_private { - - int data; /* number of data points left to be taken */ -}; - -#define devpriv ((struct dio24_private *)dev->private) - -static struct comedi_driver driver_dio24 = { - .driver_name = "ni_daq_dio24", - .module = THIS_MODULE, - .attach = dio24_attach, - .detach = dio24_detach, - .num_names = ARRAY_SIZE(dio24_boards), - .board_name = &dio24_boards[0].name, - .offset = sizeof(struct dio24_board_struct), -}; +#include "8255.h" -static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int dio24_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); struct comedi_subdevice *s; - unsigned long iobase = 0; -#ifdef incomplete - unsigned int irq = 0; -#endif - struct pcmcia_device *link; - - /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(struct dio24_private)) < 0) - return -ENOMEM; - - /* get base address, irq etc. based on bustype */ - switch (thisboard->bustype) { - case pcmcia_bustype: - link = pcmcia_cur_dev; /* XXX hack */ - if (!link) - return -EIO; - iobase = link->resource[0]->start; -#ifdef incomplete - irq = link->irq; -#endif - break; - default: - printk("bug! couldn't determine board type\n"); - return -EINVAL; - break; - } - printk("comedi%d: ni_daq_dio24: %s, io 0x%lx", dev->minor, - thisboard->name, iobase); -#ifdef incomplete - if (irq) { - printk(", irq %u", irq); - } -#endif - - printk("\n"); - - if (iobase == 0) { - printk("io base address is zero!\n"); - return -EINVAL; - } - - dev->iobase = iobase; - -#ifdef incomplete - /* grab our IRQ */ - dev->irq = irq; -#endif + int ret; - dev->board_name = thisboard->name; + link->config_flags |= CONF_AUTO_SET_IO; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; + dev->iobase = link->resource[0]->start; - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; /* 8255 dio */ - s = dev->subdevices + 0; - subdev_8255_init(dev, s, NULL, dev->iobase); - - return 0; -}; - -static int dio24_detach(struct comedi_device *dev) -{ - printk("comedi%d: ni_daq_dio24: remove\n", dev->minor); - - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 0); - - if (thisboard->bustype != pcmcia_bustype && dev->iobase) - release_region(dev->iobase, DIO24_SIZE); - if (dev->irq) - free_irq(dev->irq, dev); + s = &dev->subdevices[0]; + ret = subdev_8255_init(dev, s, NULL, dev->iobase); + if (ret) + return ret; return 0; -}; - -static void dio24_config(struct pcmcia_device *link); -static void dio24_release(struct pcmcia_device *link); -static int dio24_cs_suspend(struct pcmcia_device *p_dev); -static int dio24_cs_resume(struct pcmcia_device *p_dev); - -static int dio24_cs_attach(struct pcmcia_device *); -static void dio24_cs_detach(struct pcmcia_device *); +} -struct local_info_t { - struct pcmcia_device *link; - int stop; - struct bus_operations *bus; +static struct comedi_driver driver_dio24 = { + .driver_name = "ni_daq_dio24", + .module = THIS_MODULE, + .auto_attach = dio24_auto_attach, + .detach = comedi_pcmcia_disable, }; static int dio24_cs_attach(struct pcmcia_device *link) { - struct local_info_t *local; - - printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - CS-attach!\n"); - - dev_dbg(&link->dev, "dio24_cs_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - local->link = link; - link->priv = local; - - pcmcia_cur_dev = link; - - dio24_config(link); - - return 0; -} /* dio24_cs_attach */ - -static void dio24_cs_detach(struct pcmcia_device *link) -{ - - printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO - cs-detach!\n"); - - dev_dbg(&link->dev, "dio24_cs_detach\n"); - - ((struct local_info_t *)link->priv)->stop = 1; - dio24_release(link); - - /* This points to the parent local_info_t struct */ - kfree(link->priv); - -} /* dio24_cs_detach */ - -static int dio24_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); + return comedi_pcmcia_auto_config(link, &driver_dio24); } -static void dio24_config(struct pcmcia_device *link) -{ - int ret; - - printk(KERN_INFO "ni_daq_dio24: HOLA SOY YO! - config\n"); - - dev_dbg(&link->dev, "dio24_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | - CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, dio24_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - return; - -failed: - printk(KERN_INFO "Fallo"); - dio24_release(link); - -} /* dio24_config */ - -static void dio24_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "dio24_release\n"); - - pcmcia_disable_device(link); -} /* dio24_release */ - -static int dio24_cs_suspend(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - /* Mark the device as stopped, to block IO until later */ - local->stop = 1; - return 0; -} /* dio24_cs_suspend */ - -static int dio24_cs_resume(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - local->stop = 0; - return 0; -} /* dio24_cs_resume */ - -/*====================================================================*/ - static const struct pcmcia_device_id dio24_cs_ids[] = { - /* N.B. These IDs should match those in dio24_boards */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x475c), /* daqcard-dio24 */ PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, dio24_cs_ids); -MODULE_AUTHOR("Daniel Vecino Castel <dvecino@able.es>"); -MODULE_DESCRIPTION("Comedi driver for National Instruments " - "PCMCIA DAQ-Card DIO-24"); -MODULE_LICENSE("GPL"); -struct pcmcia_driver dio24_cs_driver = { - .probe = dio24_cs_attach, - .remove = dio24_cs_detach, - .suspend = dio24_cs_suspend, - .resume = dio24_cs_resume, - .id_table = dio24_cs_ids, - .owner = THIS_MODULE, - .name = "ni_daq_dio24", +static struct pcmcia_driver dio24_cs_driver = { + .name = "ni_daq_dio24", + .owner = THIS_MODULE, + .id_table = dio24_cs_ids, + .probe = dio24_cs_attach, + .remove = comedi_pcmcia_auto_unconfig, }; +module_comedi_pcmcia_driver(driver_dio24, dio24_cs_driver); -static int __init init_dio24_cs(void) -{ - printk("ni_daq_dio24: HOLA SOY YO!\n"); - pcmcia_register_driver(&dio24_cs_driver); - return 0; -} - -static void __exit exit_dio24_cs(void) -{ - pcmcia_unregister_driver(&dio24_cs_driver); -} - -int __init init_module(void) -{ - int ret; - - ret = init_dio24_cs(); - if (ret < 0) - return ret; - - return comedi_driver_register(&driver_dio24); -} - -void __exit cleanup_module(void) -{ - exit_dio24_cs(); - comedi_driver_unregister(&driver_dio24); -} +MODULE_AUTHOR("Daniel Vecino Castel <dvecino@able.es>"); +MODULE_DESCRIPTION( + "Comedi driver for National Instruments PCMCIA DAQ-Card DIO-24"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index ab8f37022a3..3e3f940fa57 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -1,260 +1,78 @@ /* - comedi/drivers/ni_labpc.c - Driver for National Instruments Lab-PC series boards and compatibles - Copyright (C) 2001, 2002, 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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ -*/ -/* -Driver: ni_labpc -Description: National Instruments Lab-PC (& compatibles) -Author: Frank Mori Hess <fmhess@users.sourceforge.net> -Devices: [National Instruments] Lab-PC-1200 (labpc-1200), - Lab-PC-1200AI (labpc-1200ai), Lab-PC+ (lab-pc+), PCI-1200 (ni_labpc) -Status: works - -Tested with lab-pc-1200. For the older Lab-PC+, not all input ranges -and analog references will work, the available ranges/arefs will -depend on how you have configured the jumpers on your board -(see your owner's manual). - -Kernel-level ISA plug-and-play support for the lab-pc-1200 -boards has not -yet been added to the driver, mainly due to the fact that -I don't know the device id numbers. If you have one -of these boards, -please file a bug report at http://comedi.org/ -so I can get the necessary information from you. - -The 1200 series boards have onboard calibration dacs for correcting -analog input/output offsets and gains. The proper settings for these -caldacs are stored on the board's eeprom. To read the caldac values -from the eeprom and store them into a file that can be then be used by -comedilib, use the comedi_calibrate program. - -Configuration options - ISA boards: - [0] - I/O port base address - [1] - IRQ (optional, required for timed or externally triggered conversions) - [2] - DMA channel (optional) - -Configuration options - PCI boards: - [0] - bus (optional) - [1] - slot (optional) - -The Lab-pc+ has quirky chanlist requirements -when scanning multiple channels. Multiple channel scan -sequence must start at highest channel, then decrement down to -channel 0. The rest of the cards can scan down like lab-pc+ or scan -up from channel zero. Chanlists consisting of all one channel -are also legal, and allow you to pace conversions in bursts. - -*/ + * comedi/drivers/ni_labpc.c + * Driver for National Instruments Lab-PC series boards and compatibles + * 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. + */ /* + * Driver: ni_labpc + * Description: National Instruments Lab-PC (& compatibles) + * Devices: (National Instruments) Lab-PC-1200 [lab-pc-1200] + * (National Instruments) Lab-PC-1200AI [lab-pc-1200ai] + * (National Instruments) Lab-PC+ [lab-pc+] + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Status: works + * + * Configuration options - ISA boards: + * [0] - I/O port base address + * [1] - IRQ (optional, required for timed or externally triggered + * conversions) + * [2] - DMA channel (optional) + * + * Tested with lab-pc-1200. For the older Lab-PC+, not all input + * ranges and analog references will work, the available ranges/arefs + * will depend on how you have configured the jumpers on your board + * (see your owner's manual). + * + * Kernel-level ISA plug-and-play support for the lab-pc-1200 boards + * has not yet been added to the driver, mainly due to the fact that + * I don't know the device id numbers. If you have one of these boards, + * please file a bug report at http://comedi.org/ so I can get the + * necessary information from you. + * + * The 1200 series boards have onboard calibration dacs for correcting + * analog input/output offsets and gains. The proper settings for these + * caldacs are stored on the board's eeprom. To read the caldac values + * from the eeprom and store them into a file that can be then be used + * by comedilib, use the comedi_calibrate program. + * + * The Lab-pc+ has quirky chanlist requirements when scanning multiple + * channels. Multiple channel scan sequence must start at highest channel, + * then decrement down to channel 0. The rest of the cards can scan down + * like lab-pc+ or scan up from channel zero. Chanlists consisting of all + * one channel are also legal, and allow you to pace conversions in bursts. + * + * NI manuals: + * 341309a (labpc-1200 register manual) + * 320502b (lab-pc+) + */ -NI manuals: -341309a (labpc-1200 register manual) -340914a (pci-1200) -320502b (lab-pc+) - -*/ - -#undef LABPC_DEBUG -/* #define LABPC_DEBUG enable debugging messages */ - +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/slab.h> -#include "../comedidev.h" - +#include <linux/io.h> #include <linux/delay.h> -#include <asm/dma.h> + +#include "../comedidev.h" #include "8253.h" #include "8255.h" -#include "mite.h" #include "comedi_fc.h" #include "ni_labpc.h" +#include "ni_labpc_regs.h" +#include "ni_labpc_isadma.h" -#define DRV_NAME "ni_labpc" - -/* size of io region used by board */ -#define LABPC_SIZE 32 -/* 2 MHz master clock */ -#define LABPC_TIMER_BASE 500 - -/* Registers for the lab-pc+ */ - -/* write-only registers */ -#define COMMAND1_REG 0x0 -#define ADC_GAIN_MASK (0x7 << 4) -#define ADC_CHAN_BITS(x) ((x) & 0x7) -/* enables multi channel scans */ -#define ADC_SCAN_EN_BIT 0x80 -#define COMMAND2_REG 0x1 -/* enable pretriggering (used in conjunction with SWTRIG) */ -#define PRETRIG_BIT 0x1 -/* enable paced conversions on external trigger */ -#define HWTRIG_BIT 0x2 -/* enable paced conversions */ -#define SWTRIG_BIT 0x4 -/* use two cascaded counters for pacing */ -#define CASCADE_BIT 0x8 -#define DAC_PACED_BIT(channel) (0x40 << ((channel) & 0x1)) -#define COMMAND3_REG 0x2 -/* enable dma transfers */ -#define DMA_EN_BIT 0x1 -/* enable interrupts for 8255 */ -#define DIO_INTR_EN_BIT 0x2 -/* enable dma terminal count interrupt */ -#define DMATC_INTR_EN_BIT 0x4 -/* enable timer interrupt */ -#define TIMER_INTR_EN_BIT 0x8 -/* enable error interrupt */ -#define ERR_INTR_EN_BIT 0x10 -/* enable fifo not empty interrupt */ -#define ADC_FNE_INTR_EN_BIT 0x20 -#define ADC_CONVERT_REG 0x3 -#define DAC_LSB_REG(channel) (0x4 + 2 * ((channel) & 0x1)) -#define DAC_MSB_REG(channel) (0x5 + 2 * ((channel) & 0x1)) -#define ADC_CLEAR_REG 0x8 -#define DMATC_CLEAR_REG 0xa -#define TIMER_CLEAR_REG 0xc -/* 1200 boards only */ -#define COMMAND6_REG 0xe -/* select ground or common-mode reference */ -#define ADC_COMMON_BIT 0x1 -/* adc unipolar */ -#define ADC_UNIP_BIT 0x2 -/* dac unipolar */ -#define DAC_UNIP_BIT(channel) (0x4 << ((channel) & 0x1)) -/* enable fifo half full interrupt */ -#define ADC_FHF_INTR_EN_BIT 0x20 -/* enable interrupt on end of hardware count */ -#define A1_INTR_EN_BIT 0x40 -/* scan up from channel zero instead of down to zero */ -#define ADC_SCAN_UP_BIT 0x80 -#define COMMAND4_REG 0xf -/* enables 'interval' scanning */ -#define INTERVAL_SCAN_EN_BIT 0x1 -/* enables external signal on counter b1 output to trigger scan */ -#define EXT_SCAN_EN_BIT 0x2 -/* chooses direction (output or input) for EXTCONV* line */ -#define EXT_CONVERT_OUT_BIT 0x4 -/* chooses differential inputs for adc (in conjunction with board jumper) */ -#define ADC_DIFF_BIT 0x8 -#define EXT_CONVERT_DISABLE_BIT 0x10 -/* 1200 boards only, calibration stuff */ -#define COMMAND5_REG 0x1c -/* enable eeprom for write */ -#define EEPROM_WRITE_UNPROTECT_BIT 0x4 -/* enable dithering */ -#define DITHER_EN_BIT 0x8 -/* load calibration dac */ -#define CALDAC_LOAD_BIT 0x10 -/* serial clock - rising edge writes, falling edge reads */ -#define SCLOCK_BIT 0x20 -/* serial data bit for writing to eeprom or calibration dacs */ -#define SDATA_BIT 0x40 -/* enable eeprom for read/write */ -#define EEPROM_EN_BIT 0x80 -#define INTERVAL_COUNT_REG 0x1e -#define INTERVAL_LOAD_REG 0x1f -#define INTERVAL_LOAD_BITS 0x1 - -/* read-only registers */ -#define STATUS1_REG 0x0 -/* data is available in fifo */ -#define DATA_AVAIL_BIT 0x1 -/* overrun has occurred */ -#define OVERRUN_BIT 0x2 -/* fifo overflow */ -#define OVERFLOW_BIT 0x4 -/* timer interrupt has occurred */ -#define TIMER_BIT 0x8 -/* dma terminal count has occurred */ -#define DMATC_BIT 0x10 -/* external trigger has occurred */ -#define EXT_TRIG_BIT 0x40 -/* 1200 boards only */ -#define STATUS2_REG 0x1d -/* programmable eeprom serial output */ -#define EEPROM_OUT_BIT 0x1 -/* counter A1 terminal count */ -#define A1_TC_BIT 0x2 -/* fifo not half full */ -#define FNHF_BIT 0x4 -#define ADC_FIFO_REG 0xa - -#define DIO_BASE_REG 0x10 -#define COUNTER_A_BASE_REG 0x14 -#define COUNTER_A_CONTROL_REG (COUNTER_A_BASE_REG + 0x3) -/* check modes put conversion pacer output in harmless state (a0 mode 2) */ -#define INIT_A0_BITS 0x14 -/* put hardware conversion counter output in harmless state (a1 mode 0) */ -#define INIT_A1_BITS 0x70 -#define COUNTER_B_BASE_REG 0x18 - -static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static irqreturn_t labpc_interrupt(int irq, void *d); -static int labpc_drain_fifo(struct comedi_device *dev); -static void labpc_drain_dma(struct comedi_device *dev); -static void handle_isa_dma(struct comedi_device *dev); -static void labpc_drain_dregs(struct comedi_device *dev); -static int labpc_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_calib_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_calib_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_eeprom_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int labpc_eeprom_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd); -static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd); -#ifdef CONFIG_COMEDI_PCI -static int labpc_find_device(struct comedi_device *dev, int bus, int slot); -#endif -static int labpc_dio_mem_callback(int dir, int port, int data, - unsigned long arg); -static void labpc_serial_out(struct comedi_device *dev, unsigned int value, - unsigned int num_bits); -static unsigned int labpc_serial_in(struct comedi_device *dev); -static unsigned int labpc_eeprom_read(struct comedi_device *dev, - unsigned int address); -static unsigned int labpc_eeprom_read_status(struct comedi_device *dev); -static int labpc_eeprom_write(struct comedi_device *dev, - unsigned int address, - unsigned int value); -static void write_caldac(struct comedi_device *dev, unsigned int channel, - unsigned int value); +#define LABPC_SIZE 0x20 /* size of ISA io region */ enum scan_mode { MODE_SINGLE_CHAN, @@ -263,138 +81,51 @@ enum scan_mode { MODE_MULT_CHAN_DOWN, }; -/* analog input ranges */ -#define NUM_LABPC_PLUS_AI_RANGES 16 -/* indicates unipolar ranges */ -static const int labpc_plus_is_unipolar[NUM_LABPC_PLUS_AI_RANGES] = { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, - 1, -}; - -/* map range index to gain bits */ -static const int labpc_plus_ai_gain_bits[NUM_LABPC_PLUS_AI_RANGES] = { - 0x00, - 0x10, - 0x20, - 0x30, - 0x40, - 0x50, - 0x60, - 0x70, - 0x00, - 0x10, - 0x20, - 0x30, - 0x40, - 0x50, - 0x60, - 0x70, -}; - static const struct comedi_lrange range_labpc_plus_ai = { - NUM_LABPC_PLUS_AI_RANGES, - { - 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), - } -}; - -#define NUM_LABPC_1200_AI_RANGES 14 -/* indicates unipolar ranges */ -const int labpc_1200_is_unipolar[NUM_LABPC_1200_AI_RANGES] = { - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 1, - 1, - 1, - 1, - 1, - 1, - 1, -}; -EXPORT_SYMBOL_GPL(labpc_1200_is_unipolar); - -/* map range index to gain bits */ -const int labpc_1200_ai_gain_bits[NUM_LABPC_1200_AI_RANGES] = { - 0x00, - 0x20, - 0x30, - 0x40, - 0x50, - 0x60, - 0x70, - 0x00, - 0x20, - 0x30, - 0x40, - 0x50, - 0x60, - 0x70, + 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) + } }; -EXPORT_SYMBOL_GPL(labpc_1200_ai_gain_bits); -const struct comedi_lrange range_labpc_1200_ai = { - NUM_LABPC_1200_AI_RANGES, - { - 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_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) + } }; -EXPORT_SYMBOL_GPL(range_labpc_1200_ai); -/* analog output ranges */ -#define AO_RANGE_IS_UNIPOLAR 0x1 static const struct comedi_lrange range_labpc_ao = { - 2, - { - BIP_RANGE(5), - UNI_RANGE(10), - } + 2, { + BIP_RANGE(5), + UNI_RANGE(10) + } }; /* functions that do inb/outb and readb/writeb so we can use @@ -411,554 +142,267 @@ static inline void labpc_outb(unsigned int byte, unsigned long address) static inline unsigned int labpc_readb(unsigned long address) { - return readb((void *)address); + return readb((void __iomem *)address); } static inline void labpc_writeb(unsigned int byte, unsigned long address) { - writeb(byte, (void *)address); + writeb(byte, (void __iomem *)address); } -static const struct labpc_board_struct labpc_boards[] = { - { - .name = "lab-pc-1200", - .ai_speed = 10000, - .bustype = isa_bustype, - .register_layout = labpc_1200_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, - .ai_range_is_unipolar = labpc_1200_is_unipolar, - .ai_scan_up = 1, - .memory_mapped_io = 0, - }, - { - .name = "lab-pc-1200ai", - .ai_speed = 10000, - .bustype = isa_bustype, - .register_layout = labpc_1200_layout, - .has_ao = 0, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, - .ai_range_is_unipolar = labpc_1200_is_unipolar, - .ai_scan_up = 1, - .memory_mapped_io = 0, - }, - { - .name = "lab-pc+", - .ai_speed = 12000, - .bustype = isa_bustype, - .register_layout = labpc_plus_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_plus_ai, - .ai_range_code = labpc_plus_ai_gain_bits, - .ai_range_is_unipolar = labpc_plus_is_unipolar, - .ai_scan_up = 0, - .memory_mapped_io = 0, - }, -#ifdef CONFIG_COMEDI_PCI - { - .name = "pci-1200", - .device_id = 0x161, - .ai_speed = 10000, - .bustype = pci_bustype, - .register_layout = labpc_1200_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, - .ai_range_is_unipolar = labpc_1200_is_unipolar, - .ai_scan_up = 1, - .memory_mapped_io = 1, - }, -/* dummy entry so pci board works when comedi_config is passed driver name */ +#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISA) +static const struct labpc_boardinfo labpc_boards[] = { { - .name = DRV_NAME, - .bustype = pci_bustype, - }, -#endif -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((struct labpc_board_struct *)dev->board_ptr) - -/* size in bytes of dma buffer */ -static const int dma_buffer_size = 0xff00; -/* 2 bytes per sample */ -static const int sample_size = 2; - -#define devpriv ((struct labpc_private *)dev->private) - -static struct comedi_driver driver_labpc = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = labpc_attach, - .detach = labpc_common_detach, - .num_names = ARRAY_SIZE(labpc_boards), - .board_name = &labpc_boards[0].name, - .offset = sizeof(struct labpc_board_struct), -}; - -#ifdef CONFIG_COMEDI_PCI -static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)}, - {0} + .name = "lab-pc-1200", + .ai_speed = 10000, + .ai_scan_up = 1, + .has_ao = 1, + .is_labpc1200 = 1, + }, { + .name = "lab-pc-1200ai", + .ai_speed = 10000, + .ai_scan_up = 1, + .is_labpc1200 = 1, + }, { + .name = "lab-pc+", + .ai_speed = 12000, + .has_ao = 1, + }, }; +#endif -MODULE_DEVICE_TABLE(pci, labpc_pci_table); -#endif /* CONFIG_COMEDI_PCI */ - -static inline int labpc_counter_load(struct comedi_device *dev, - unsigned long base_address, - unsigned int counter_number, - unsigned int count, unsigned int mode) +static void labpc_counter_load(struct comedi_device *dev, + unsigned long base_address, + unsigned int counter_number, + unsigned int count, + unsigned int mode) { - if (thisboard->memory_mapped_io) - return i8254_mm_load((void *)base_address, 0, counter_number, - count, mode); - else - return i8254_load(base_address, 0, counter_number, count, mode); -} + const struct labpc_boardinfo *board = comedi_board(dev); -int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, - unsigned int irq, unsigned int dma_chan) -{ - struct comedi_subdevice *s; - int i; - unsigned long dma_flags, isr_flags; - short lsb, msb; - - printk(KERN_ERR "comedi%d: ni_labpc: %s, io 0x%lx", dev->minor, - thisboard->name, - iobase); - if (irq) - printk(", irq %u", irq); - if (dma_chan) - printk(", dma %u", dma_chan); - printk("\n"); - - if (iobase == 0) { - printk(KERN_ERR "io base address is zero!\n"); - return -EINVAL; - } - /* request io regions for isa boards */ - if (thisboard->bustype == isa_bustype) { - /* check if io addresses are available */ - if (!request_region(iobase, LABPC_SIZE, - driver_labpc.driver_name)) { - printk(KERN_ERR "I/O port conflict\n"); - return -EIO; - } - } - dev->iobase = iobase; + if (board->has_mmio) { + void __iomem *mmio_base = (void __iomem *)base_address; - if (thisboard->memory_mapped_io) { - devpriv->read_byte = labpc_readb; - devpriv->write_byte = labpc_writeb; + i8254_mm_set_mode(mmio_base, 0, counter_number, mode); + i8254_mm_write(mmio_base, 0, counter_number, count); } else { - devpriv->read_byte = labpc_inb; - devpriv->write_byte = labpc_outb; + i8254_set_mode(base_address, 0, counter_number, mode); + i8254_write(base_address, 0, counter_number, count); } - /* initialize board's command registers */ - devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); - devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); - devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); - if (thisboard->register_layout == labpc_1200_layout) { - devpriv->write_byte(devpriv->command5_bits, - dev->iobase + COMMAND5_REG); - devpriv->write_byte(devpriv->command6_bits, - dev->iobase + COMMAND6_REG); - } - - /* grab our IRQ */ - if (irq) { - isr_flags = 0; - if (thisboard->bustype == pci_bustype - || thisboard->bustype == pcmcia_bustype) - isr_flags |= IRQF_SHARED; - if (request_irq(irq, labpc_interrupt, isr_flags, - driver_labpc.driver_name, dev)) { - printk(KERN_ERR "unable to allocate irq %u\n", irq); - return -EINVAL; - } - } - dev->irq = irq; - - /* grab dma channel */ - if (dma_chan > 3) { - printk(KERN_ERR " invalid dma channel %u\n", dma_chan); - return -EINVAL; - } else if (dma_chan) { - /* allocate dma buffer */ - devpriv->dma_buffer = - kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA); - if (devpriv->dma_buffer == NULL) { - printk(KERN_ERR " failed to allocate dma buffer\n"); - return -ENOMEM; - } - if (request_dma(dma_chan, driver_labpc.driver_name)) { - printk(KERN_ERR " failed to allocate dma channel %u\n", - dma_chan); - return -EINVAL; - } - devpriv->dma_chan = dma_chan; - dma_flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); - release_dma_lock(dma_flags); - } - - dev->board_name = thisboard->name; +} - if (alloc_subdevices(dev, 5) < 0) - return -ENOMEM; +static void labpc_counter_set_mode(struct comedi_device *dev, + unsigned long base_address, + unsigned int counter_number, + unsigned int mode) +{ + const struct labpc_boardinfo *board = comedi_board(dev); - /* analog input subdevice */ - s = dev->subdevices + 0; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ; - s->n_chan = 8; - s->len_chanlist = 8; - s->maxdata = (1 << 12) - 1; /* 12 bit resolution */ - s->range_table = thisboard->ai_range_table; - s->do_cmd = labpc_ai_cmd; - s->do_cmdtest = labpc_ai_cmdtest; - s->insn_read = labpc_ai_rinsn; - s->cancel = labpc_cancel; + if (board->has_mmio) { + void __iomem *mmio_base = (void __iomem *)base_address; - /* analog output */ - s = dev->subdevices + 1; - if (thisboard->has_ao) { - /* - * Could provide command support, except it only has a - * one sample hardware buffer for analog output and no - * underrun flag. - */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; - s->n_chan = NUM_AO_CHAN; - s->maxdata = (1 << 12) - 1; /* 12 bit resolution */ - s->range_table = &range_labpc_ao; - s->insn_read = labpc_ao_rinsn; - s->insn_write = labpc_ao_winsn; - /* initialize analog outputs to a known value */ - for (i = 0; i < s->n_chan; i++) { - devpriv->ao_value[i] = s->maxdata / 2; - lsb = devpriv->ao_value[i] & 0xff; - msb = (devpriv->ao_value[i] >> 8) & 0xff; - devpriv->write_byte(lsb, dev->iobase + DAC_LSB_REG(i)); - devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i)); - } + i8254_mm_set_mode(mmio_base, 0, counter_number, mode); } else { - s->type = COMEDI_SUBD_UNUSED; + i8254_set_mode(base_address, 0, counter_number, mode); } +} - /* 8255 dio */ - s = dev->subdevices + 2; - /* if board uses io memory we have to give a custom callback - * function to the 8255 driver */ - if (thisboard->memory_mapped_io) - subdev_8255_init(dev, s, labpc_dio_mem_callback, - (unsigned long)(dev->iobase + DIO_BASE_REG)); - else - subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG); - - /* calibration subdevices for boards that have one */ - s = dev->subdevices + 3; - if (thisboard->register_layout == labpc_1200_layout) { - 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_read_insn; - s->insn_write = labpc_calib_write_insn; +static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct labpc_private *devpriv = dev->private; + unsigned long flags; - for (i = 0; i < s->n_chan; i++) - write_caldac(dev, i, s->maxdata / 2); - } else - s->type = COMEDI_SUBD_UNUSED; + spin_lock_irqsave(&dev->spinlock, flags); + devpriv->cmd2 &= ~(CMD2_SWTRIG | CMD2_HWTRIG | CMD2_PRETRIG); + devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG); + spin_unlock_irqrestore(&dev->spinlock, flags); - /* EEPROM */ - s = dev->subdevices + 4; - if (thisboard->register_layout == labpc_1200_layout) { - 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_read_insn; - s->insn_write = labpc_eeprom_write_insn; - - for (i = 0; i < EEPROM_SIZE; i++) - devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i); -#ifdef LABPC_DEBUG - printk(KERN_ERR " eeprom:"); - for (i = 0; i < EEPROM_SIZE; i++) - printk(" %i:0x%x ", i, devpriv->eeprom_data[i]); - printk("\n"); -#endif - } else - s->type = COMEDI_SUBD_UNUSED; + devpriv->cmd3 = 0; + devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG); return 0; } -EXPORT_SYMBOL_GPL(labpc_common_attach); -static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) +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) { - unsigned long iobase = 0; - unsigned int irq = 0; - unsigned int dma_chan = 0; -#ifdef CONFIG_COMEDI_PCI - int retval; -#endif - - /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(struct labpc_private)) < 0) - return -ENOMEM; + const struct labpc_boardinfo *board = comedi_board(dev); + struct labpc_private *devpriv = dev->private; - /* get base address, irq etc. based on bustype */ - switch (thisboard->bustype) { - case isa_bustype: - iobase = it->options[0]; - irq = it->options[1]; - dma_chan = it->options[2]; - break; - case pci_bustype: -#ifdef CONFIG_COMEDI_PCI - retval = labpc_find_device(dev, it->options[0], it->options[1]); - if (retval < 0) - return retval; - retval = mite_setup(devpriv->mite); - if (retval < 0) - return retval; - iobase = (unsigned long)devpriv->mite->daq_io_addr; - irq = mite_irq(devpriv->mite); -#else - printk(KERN_ERR " this driver has not been built with PCI " - "support.\n"); - return -EINVAL; -#endif - break; - case pcmcia_bustype: - printk - (" this driver does not support pcmcia cards, use ni_labpc_cs.o\n"); - return -EINVAL; - break; - default: - printk(KERN_ERR "bug! couldn't determine board type\n"); - return -EINVAL; - break; + 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); } - return labpc_common_attach(dev, iobase, irq, dma_chan); -} + /* 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); -/* adapted from ni_pcimio for finding mite based boards (pc-1200) */ -#ifdef CONFIG_COMEDI_PCI -static int labpc_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; -/* if bus/slot are specified then make sure we have the right bus/slot */ - if (bus || slot) { - if (bus != mite->pcidev->bus->number - || slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < driver_labpc.num_names; i++) { - if (labpc_boards[i].bustype != pci_bustype) - continue; - if (mite_device_id(mite) == labpc_boards[i].device_id) { - devpriv->mite = mite; -/* fixup board pointer, in case we were using the dummy "ni_labpc" entry */ - dev->board_ptr = &labpc_boards[i]; - return 0; - } - } - } - printk(KERN_ERR "no device found\n"); - mite_list_devices(); - return -EIO; + devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG); } -#endif -int labpc_common_detach(struct comedi_device *dev) +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) { - printk(KERN_ERR "comedi%d: ni_labpc: detach\n", dev->minor); - - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 2); + const struct labpc_boardinfo *board = comedi_board(dev); + struct labpc_private *devpriv = dev->private; - /* only free stuff if it has been allocated by _attach */ - kfree(devpriv->dma_buffer); - if (devpriv->dma_chan) - free_dma(devpriv->dma_chan); - if (dev->irq) - free_irq(dev->irq, dev); - if (thisboard->bustype == isa_bustype && dev->iobase) - release_region(dev->iobase, LABPC_SIZE); -#ifdef CONFIG_COMEDI_PCI - if (devpriv->mite) - mite_unsetup(devpriv->mite); -#endif + if (!board->is_labpc1200) + return; - return 0; -}; -EXPORT_SYMBOL_GPL(labpc_common_detach); + /* reference inputs to ground or common? */ + if (aref != AREF_GROUND) + devpriv->cmd6 |= CMD6_NRSE; + else + devpriv->cmd6 &= ~CMD6_NRSE; -static void labpc_clear_adc_fifo(const struct comedi_device *dev) -{ - devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); - devpriv->read_byte(dev->iobase + ADC_FIFO_REG); - devpriv->read_byte(dev->iobase + ADC_FIFO_REG); -} + /* bipolar or unipolar range? */ + if (comedi_range_is_unipolar(s, range)) + devpriv->cmd6 |= CMD6_ADCUNI; + else + devpriv->cmd6 &= ~CMD6_ADCUNI; -static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s) -{ - unsigned long flags; + /* interrupt on fifo half full? */ + if (xfer == fifo_half_full_transfer) + devpriv->cmd6 |= CMD6_HFINTEN; + else + devpriv->cmd6 &= ~CMD6_HFINTEN; - spin_lock_irqsave(&dev->spinlock, flags); - devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; - devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); + /* enable interrupt on counter a1 terminal count? */ + if (ena_intr) + devpriv->cmd6 |= CMD6_DQINTEN; + else + devpriv->cmd6 &= ~CMD6_DQINTEN; - devpriv->command3_bits = 0; - devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); + /* are we scanning up or down through channels? */ + if (mode == MODE_MULT_CHAN_UP) + devpriv->cmd6 |= CMD6_SCANUP; + else + devpriv->cmd6 &= ~CMD6_SCANUP; - return 0; + devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG); } -static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) +static unsigned int labpc_read_adc_fifo(struct comedi_device *dev) { - if (cmd->chanlist_len == 1) - return MODE_SINGLE_CHAN; + struct labpc_private *devpriv = dev->private; + unsigned int lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG); + unsigned int msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG); - /* chanlist may be NULL during cmdtest. */ - if (cmd->chanlist == NULL) - return MODE_MULT_CHAN_UP; - - if (CR_CHAN(cmd->chanlist[0]) == CR_CHAN(cmd->chanlist[1])) - return MODE_SINGLE_CHAN_INTERVAL; + return (msb << 8) | lsb; +} - if (CR_CHAN(cmd->chanlist[0]) < CR_CHAN(cmd->chanlist[1])) - return MODE_MULT_CHAN_UP; +static void labpc_clear_adc_fifo(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; - if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1])) - return MODE_MULT_CHAN_DOWN; + devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); + labpc_read_adc_fifo(dev); +} - printk(KERN_ERR "ni_labpc: bug! this should never happen\n"); +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; - return 0; + devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); + if (devpriv->stat1 & STAT1_DAVAIL) + return 0; + return -EBUSY; } -static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, - const struct comedi_cmd *cmd) +static int labpc_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int mode, channel, range, aref, i; + 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; - if (cmd->chanlist == NULL) - return 0; + /* disable timed conversions, interrupt generation and dma */ + labpc_cancel(dev, s); - mode = labpc_ai_scan_mode(cmd); + labpc_ai_set_chan_and_gain(dev, MODE_SINGLE_CHAN, chan, range, aref); - if (mode == MODE_SINGLE_CHAN) - return 0; + labpc_setup_cmd6_reg(dev, s, MODE_SINGLE_CHAN, fifo_not_empty_transfer, + range, aref, false); - if (mode == MODE_SINGLE_CHAN_INTERVAL) { - if (cmd->chanlist_len > 0xff) { - comedi_error(dev, - "ni_labpc: chanlist too long for single channel interval mode\n"); - return 1; - } - } + /* setup cmd4 register */ + devpriv->cmd4 = 0; + devpriv->cmd4 |= CMD4_ECLKRCV; + /* single-ended/differential */ + if (aref == AREF_DIFF) + devpriv->cmd4 |= CMD4_SEDIFF; + devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG); - channel = CR_CHAN(cmd->chanlist[0]); - range = CR_RANGE(cmd->chanlist[0]); - aref = CR_AREF(cmd->chanlist[0]); + /* initialize pacer counter to prevent any problems */ + labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, I8254_MODE2); - for (i = 0; i < cmd->chanlist_len; i++) { + labpc_clear_adc_fifo(dev); - switch (mode) { - case MODE_SINGLE_CHAN_INTERVAL: - if (CR_CHAN(cmd->chanlist[i]) != channel) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; - } - break; - case MODE_MULT_CHAN_UP: - if (CR_CHAN(cmd->chanlist[i]) != i) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; - } - break; - case MODE_MULT_CHAN_DOWN: - if (CR_CHAN(cmd->chanlist[i]) != - cmd->chanlist_len - i - 1) { - comedi_error(dev, - "channel scanning order specified in chanlist is not supported by hardware.\n"); - return 1; - } - break; - default: - printk(KERN_ERR "ni_labpc: bug! in chanlist check\n"); - return 1; - break; - } + for (i = 0; i < insn->n; i++) { + /* trigger conversion */ + devpriv->write_byte(0x1, dev->iobase + ADC_START_CONVERT_REG); - if (CR_RANGE(cmd->chanlist[i]) != range) { - comedi_error(dev, - "entries in chanlist must all have the same range\n"); - return 1; - } + ret = comedi_timeout(dev, s, insn, labpc_ai_eoc, 0); + if (ret) + return ret; - if (CR_AREF(cmd->chanlist[i]) != aref) { - comedi_error(dev, - "entries in chanlist must all have the same reference\n"); - return 1; - } + data[i] = labpc_read_adc_fifo(dev); } - return 0; + return insn->n; } -static int labpc_use_continuous_mode(const struct comedi_cmd *cmd) +static bool labpc_use_continuous_mode(const struct comedi_cmd *cmd, + enum scan_mode mode) { - if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN) - return 1; + if (mode == MODE_SINGLE_CHAN || cmd->scan_begin_src == TRIG_FOLLOW) + return true; - if (cmd->scan_begin_src == TRIG_FOLLOW) - return 1; - - return 0; + return false; } -static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd) +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 (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN && - cmd->scan_begin_src == TRIG_TIMER) + 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, unsigned int ns) +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 (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN && + if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER) { cmd->scan_begin_arg = ns; if (cmd->convert_arg > cmd->scan_begin_arg) @@ -967,83 +411,239 @@ static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, unsigned int ns) cmd->convert_arg = ns; } -static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd) +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 (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN && - cmd->convert_src == TRIG_TIMER) + 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, unsigned int ns) +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 (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN && - cmd->convert_src == TRIG_TIMER) + 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) +{ + if (cmd->chanlist_len == 1) + return MODE_SINGLE_CHAN; + + /* chanlist may be NULL during cmdtest. */ + if (cmd->chanlist == NULL) + return MODE_MULT_CHAN_UP; + + if (CR_CHAN(cmd->chanlist[0]) == CR_CHAN(cmd->chanlist[1])) + return MODE_SINGLE_CHAN_INTERVAL; + + if (CR_CHAN(cmd->chanlist[0]) < CR_CHAN(cmd->chanlist[1])) + return MODE_MULT_CHAN_UP; + + if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1])) + return MODE_MULT_CHAN_DOWN; + + pr_err("ni_labpc: bug! cannot determine AI scan mode\n"); + return 0; +} + +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; - int stop_mask; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + unsigned int stop_mask; + enum scan_mode mode; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + 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); - tmp = cmd->stop_src; stop_mask = TRIG_COUNT | TRIG_NONE; - if (thisboard->register_layout == labpc_1200_layout) + if (board->is_labpc1200) stop_mask |= TRIG_EXT; - cmd->stop_src &= stop_mask; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE) - err++; + 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) @@ -1052,56 +652,40 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg == TRIG_NOW && cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; + 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++; + err |= -EINVAL; + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + board->ai_speed); - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < thisboard->ai_speed) { - cmd->convert_arg = thisboard->ai_speed; - err++; - } - } /* make sure scan timing is not too fast */ if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->convert_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->chanlist_len) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->chanlist_len; - err++; - } - if (cmd->scan_begin_arg < - thisboard->ai_speed * cmd->chanlist_len) { - cmd->scan_begin_arg = - thisboard->ai_speed * cmd->chanlist_len; - err++; - } + 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); } - /* stop source */ + switch (cmd->stop_src) { case TRIG_COUNT: - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); break; case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); break; /* * TRIG_EXT doesn't care since it doesn't @@ -1118,14 +702,19 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, tmp = cmd->convert_arg; tmp2 = cmd->scan_begin_arg; - labpc_adc_timing(dev, cmd); + 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; - if (labpc_ai_chanlist_invalid(dev, cmd)) + /* 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; @@ -1133,30 +722,22 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - int channel, range, aref; - unsigned long irq_flags; - int ret; + 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; - if (!dev->irq) { - comedi_error(dev, "no irq assigned, cannot perform command"); - return -1; - } - - range = CR_RANGE(cmd->chanlist[0]); - aref = CR_AREF(cmd->chanlist[0]); - /* make sure board is disabled before setting up acquisition */ - spin_lock_irqsave(&dev->spinlock, flags); - devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; - devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - devpriv->command3_bits = 0; - devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); + labpc_cancel(dev, s); /* initialize software conversion count */ if (cmd->stop_src == TRIG_COUNT) @@ -1168,511 +749,255 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) * load counter a1 with count of 3 * (pc+ manual says this is minimum allowed) using mode 0 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, - 1, 3, 0); - if (ret < 0) { - comedi_error(dev, "error loading counter a1"); - return -1; - } - } else /* - * otherwise, just put a1 in mode 0 - * with no count to set its output low - */ - devpriv->write_byte(INIT_A1_BITS, - dev->iobase + COUNTER_A_CONTROL_REG); - - /* figure out what method we will use to transfer data */ - if (devpriv->dma_chan && /* need a dma channel allocated */ - /* - * dma unsafe at RT priority, - * and too much setup time for TRIG_WAKE_EOS for - */ - (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) == 0 && - /* only available on the isa boards */ - thisboard->bustype == isa_bustype) { + labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, + 1, 3, I8254_MODE0); + } else { + /* just put counter a1 in mode 0 to set its output low */ + labpc_counter_set_mode(dev, dev->iobase + 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; - /* pc-plus has no fifo-half full interrupt */ - } else if (thisboard->register_layout == labpc_1200_layout && - /* 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)) { + 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 + else xfer = fifo_not_empty_transfer; devpriv->current_transfer = xfer; - /* setup command6 register for 1200 boards */ - if (thisboard->register_layout == labpc_1200_layout) { - /* reference inputs to ground or common? */ - if (aref != AREF_GROUND) - devpriv->command6_bits |= ADC_COMMON_BIT; - else - devpriv->command6_bits &= ~ADC_COMMON_BIT; - /* bipolar or unipolar range? */ - if (thisboard->ai_range_is_unipolar[range]) - devpriv->command6_bits |= ADC_UNIP_BIT; - else - devpriv->command6_bits &= ~ADC_UNIP_BIT; - /* interrupt on fifo half full? */ - if (xfer == fifo_half_full_transfer) - devpriv->command6_bits |= ADC_FHF_INTR_EN_BIT; - else - devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT; - /* enable interrupt on counter a1 terminal count? */ - if (cmd->stop_src == TRIG_EXT) - devpriv->command6_bits |= A1_INTR_EN_BIT; - else - devpriv->command6_bits &= ~A1_INTR_EN_BIT; - /* are we scanning up or down through channels? */ - if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP) - devpriv->command6_bits |= ADC_SCAN_UP_BIT; - else - devpriv->command6_bits &= ~ADC_SCAN_UP_BIT; - /* write to register */ - devpriv->write_byte(devpriv->command6_bits, - dev->iobase + COMMAND6_REG); - } + 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)); - /* setup channel list, etc (command1 register) */ - devpriv->command1_bits = 0; - if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP) - channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); - else - channel = CR_CHAN(cmd->chanlist[0]); - /* munge channel bits for differential / scan disabled mode */ - if (labpc_ai_scan_mode(cmd) != MODE_SINGLE_CHAN && aref == AREF_DIFF) - channel *= 2; - devpriv->command1_bits |= ADC_CHAN_BITS(channel); - devpriv->command1_bits |= thisboard->ai_range_code[range]; - devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); /* manual says to set scan enable bit on second pass */ - if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP || - labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_DOWN) { - devpriv->command1_bits |= ADC_SCAN_EN_BIT; + 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(devpriv->command1_bits, - dev->iobase + COMMAND1_REG); + devpriv->write_byte(devpriv->cmd1, dev->iobase + CMD1_REG); } - /* setup any external triggering/pacing (command4 register) */ - devpriv->command4_bits = 0; - if (cmd->convert_src != TRIG_EXT) - devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; - /* 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) == 0) { - devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT; - if (cmd->scan_begin_src == TRIG_EXT) - devpriv->command4_bits |= EXT_SCAN_EN_BIT; - } - /* single-ended/differential */ - if (aref == AREF_DIFF) - devpriv->command4_bits |= ADC_DIFF_BIT; - devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); devpriv->write_byte(cmd->chanlist_len, dev->iobase + INTERVAL_COUNT_REG); /* load count */ - devpriv->write_byte(INTERVAL_LOAD_BITS, - dev->iobase + INTERVAL_LOAD_REG); + devpriv->write_byte(0x1, dev->iobase + INTERVAL_STROBE_REG); - if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) { + if (cmd->convert_src == TRIG_TIMER || + cmd->scan_begin_src == TRIG_TIMER) { /* set up pacing */ - labpc_adc_timing(dev, cmd); + labpc_adc_timing(dev, cmd, mode); /* load counter b0 in mode 3 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, - 0, devpriv->divisor_b0, 3); - if (ret < 0) { - comedi_error(dev, "error loading counter b0"); - return -1; - } + labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, + 0, devpriv->divisor_b0, I8254_MODE3); } /* set up conversion pacing */ - if (labpc_ai_convert_period(cmd)) { + if (labpc_ai_convert_period(cmd, mode)) { /* load counter a0 in mode 2 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, - 0, devpriv->divisor_a0, 2); - if (ret < 0) { - comedi_error(dev, "error loading counter a0"); - return -1; - } - } else - devpriv->write_byte(INIT_A0_BITS, - dev->iobase + COUNTER_A_CONTROL_REG); + labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, devpriv->divisor_a0, I8254_MODE2); + } else { + /* initialize pacer counter to prevent any problems */ + labpc_counter_set_mode(dev, dev->iobase + COUNTER_A_BASE_REG, + 0, I8254_MODE2); + } /* set up scan pacing */ - if (labpc_ai_scan_period(cmd)) { + if (labpc_ai_scan_period(cmd, mode)) { /* load counter b1 in mode 2 */ - ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, - 1, devpriv->divisor_b1, 2); - if (ret < 0) { - comedi_error(dev, "error loading counter b1"); - return -1; - } + labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, + 1, devpriv->divisor_b1, I8254_MODE2); } labpc_clear_adc_fifo(dev); - /* set up dma transfer */ - if (xfer == isa_dma_transfer) { - irq_flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma_chan); - set_dma_addr(devpriv->dma_chan, - virt_to_bus(devpriv->dma_buffer)); - /* set appropriate size of transfer */ - devpriv->dma_transfer_size = labpc_suggest_transfer_size(*cmd); - if (cmd->stop_src == TRIG_COUNT && - devpriv->count * sample_size < devpriv->dma_transfer_size) { - devpriv->dma_transfer_size = - devpriv->count * sample_size; - } - set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); - enable_dma(devpriv->dma_chan); - release_dma_lock(irq_flags); - /* enable board's dma */ - devpriv->command3_bits |= DMA_EN_BIT | DMATC_INTR_EN_BIT; - } else - devpriv->command3_bits &= ~DMA_EN_BIT & ~DMATC_INTR_EN_BIT; + if (xfer == isa_dma_transfer) + labpc_setup_dma(dev, s); /* enable error interrupts */ - devpriv->command3_bits |= ERR_INTR_EN_BIT; + devpriv->cmd3 |= CMD3_ERRINTEN; /* enable fifo not empty interrupt? */ if (xfer == fifo_not_empty_transfer) - devpriv->command3_bits |= ADC_FNE_INTR_EN_BIT; - else - devpriv->command3_bits &= ~ADC_FNE_INTR_EN_BIT; - devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); + devpriv->cmd3 |= CMD3_FIFOINTEN; + devpriv->write_byte(devpriv->cmd3, dev->iobase + 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(devpriv->cmd4, dev->iobase + CMD4_REG); /* startup acquisition */ - /* command2 reg */ - /* use 2 cascaded counters for pacing */ spin_lock_irqsave(&dev->spinlock, flags); - devpriv->command2_bits |= CASCADE_BIT; - switch (cmd->start_src) { - case TRIG_EXT: - devpriv->command2_bits |= HWTRIG_BIT; - devpriv->command2_bits &= ~PRETRIG_BIT & ~SWTRIG_BIT; - break; - case TRIG_NOW: - devpriv->command2_bits |= SWTRIG_BIT; - devpriv->command2_bits &= ~PRETRIG_BIT & ~HWTRIG_BIT; - break; - default: - comedi_error(dev, "bug with start_src"); - return -1; - break; + + /* 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(devpriv->cmd2, dev->iobase + 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->iobase + 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->iobase + STAT1_REG); } - switch (cmd->stop_src) { - case TRIG_EXT: - devpriv->command2_bits |= HWTRIG_BIT | PRETRIG_BIT; - break; - case TRIG_COUNT: - case TRIG_NONE: - break; - default: - comedi_error(dev, "bug with stop_src"); + if (i == timeout) { + comedi_error(dev, "ai timeout, fifo never empties"); + async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; return -1; } - devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); 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 == 0) { + if (!dev->attached) { comedi_error(dev, "premature interrupt"); return IRQ_HANDLED; } async = s->async; cmd = &async->cmd; - async->events = 0; /* read board status */ - devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG); - if (thisboard->register_layout == labpc_1200_layout) - devpriv->status2_bits = - devpriv->read_byte(dev->iobase + STATUS2_REG); - - if ((devpriv->status1_bits & (DMATC_BIT | TIMER_BIT | OVERFLOW_BIT | - OVERRUN_BIT | DATA_AVAIL_BIT)) == 0 - && (devpriv->status2_bits & A1_TC_BIT) == 0 - && (devpriv->status2_bits & FNHF_BIT)) { + devpriv->stat1 = devpriv->read_byte(dev->iobase + STAT1_REG); + if (board->is_labpc1200) + devpriv->stat2 = devpriv->read_byte(dev->iobase + 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->status1_bits & OVERRUN_BIT) { + if (devpriv->stat1 & STAT1_OVERRUN) { /* clear error interrupt */ - devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); + devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overrun"); return IRQ_HANDLED; } - if (devpriv->current_transfer == isa_dma_transfer) { - /* - * if a dma terminal count of external stop trigger - * has occurred - */ - if (devpriv->status1_bits & DMATC_BIT || - (thisboard->register_layout == labpc_1200_layout - && devpriv->status2_bits & A1_TC_BIT)) { - handle_isa_dma(dev); - } - } else + if (devpriv->current_transfer == isa_dma_transfer) + labpc_handle_dma_status(dev); + else labpc_drain_fifo(dev); - if (devpriv->status1_bits & TIMER_BIT) { + if (devpriv->stat1 & STAT1_CNTINT) { comedi_error(dev, "handled timer interrupt?"); /* clear it */ devpriv->write_byte(0x1, dev->iobase + TIMER_CLEAR_REG); } - if (devpriv->status1_bits & OVERFLOW_BIT) { + if (devpriv->stat1 & STAT1_OVERFLOW) { /* clear error interrupt */ - devpriv->write_byte(0x1, dev->iobase + ADC_CLEAR_REG); + devpriv->write_byte(0x1, dev->iobase + ADC_FIFO_CLEAR_REG); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, s); + cfc_handle_events(dev, s); comedi_error(dev, "overflow"); return IRQ_HANDLED; } /* handle external stop trigger */ if (cmd->stop_src == TRIG_EXT) { - if (devpriv->status2_bits & A1_TC_BIT) { + if (devpriv->stat2 & STAT2_OUTA1) { labpc_drain_dregs(dev); - labpc_cancel(dev, s); async->events |= COMEDI_CB_EOA; } } /* TRIG_COUNT end of acquisition */ if (cmd->stop_src == TRIG_COUNT) { - if (devpriv->count == 0) { - labpc_cancel(dev, s); + if (devpriv->count == 0) async->events |= COMEDI_CB_EOA; - } } - comedi_event(dev, s); + cfc_handle_events(dev, s); return IRQ_HANDLED; } -/* read all available samples from ai fifo */ -static int labpc_drain_fifo(struct comedi_device *dev) -{ - unsigned int lsb, msb; - short data; - struct comedi_async *async = dev->read_subdev->async; - const int timeout = 10000; - unsigned int i; - - devpriv->status1_bits = devpriv->read_byte(dev->iobase + STATUS1_REG); - - for (i = 0; (devpriv->status1_bits & DATA_AVAIL_BIT) && i < timeout; - i++) { - /* quit if we have all the data we want */ - if (async->cmd.stop_src == TRIG_COUNT) { - if (devpriv->count == 0) - break; - devpriv->count--; - } - lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG); - msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG); - data = (msb << 8) | lsb; - cfc_write_to_buffer(dev->read_subdev, data); - devpriv->status1_bits = - devpriv->read_byte(dev->iobase + STATUS1_REG); - } - if (i == timeout) { - comedi_error(dev, "ai timeout, fifo never empties"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - return -1; - } - - return 0; -} - -static void labpc_drain_dma(struct comedi_device *dev) -{ - struct comedi_subdevice *s = dev->read_subdev; - struct comedi_async *async = s->async; - int status; - unsigned long flags; - unsigned int max_points, num_points, residue, leftover; - int i; - - status = devpriv->status1_bits; - - flags = claim_dma_lock(); - disable_dma(devpriv->dma_chan); - /* clear flip-flop to make sure 2-byte registers for - * count and address get set correctly */ - clear_dma_ff(devpriv->dma_chan); - - /* figure out how many points to read */ - max_points = devpriv->dma_transfer_size / sample_size; - /* residue is the number of points left to be done on the dma - * transfer. It should always be zero at this point unless - * the stop_src is set to external triggering. - */ - residue = get_dma_residue(devpriv->dma_chan) / sample_size; - num_points = max_points - residue; - if (devpriv->count < num_points && async->cmd.stop_src == TRIG_COUNT) - num_points = devpriv->count; - - /* figure out how many points will be stored next time */ - leftover = 0; - if (async->cmd.stop_src != TRIG_COUNT) { - leftover = devpriv->dma_transfer_size / sample_size; - } else if (devpriv->count > num_points) { - leftover = devpriv->count - num_points; - if (leftover > max_points) - leftover = max_points; - } - - /* write data to comedi buffer */ - for (i = 0; i < num_points; i++) - cfc_write_to_buffer(s, devpriv->dma_buffer[i]); - - if (async->cmd.stop_src == TRIG_COUNT) - devpriv->count -= num_points; - - /* set address and count for next transfer */ - set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer)); - set_dma_count(devpriv->dma_chan, leftover * sample_size); - release_dma_lock(flags); - - async->events |= COMEDI_CB_BLOCK; -} - -static void handle_isa_dma(struct comedi_device *dev) -{ - labpc_drain_dma(dev); - - enable_dma(devpriv->dma_chan); - - /* clear dma tc interrupt */ - devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG); -} - -/* 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) -{ - if (devpriv->current_transfer == isa_dma_transfer) - labpc_drain_dma(dev); - - labpc_drain_fifo(dev); -} - -static int labpc_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i, n; - int chan, range; - int lsb, msb; - int timeout = 1000; - unsigned long flags; - - /* disable timed conversions */ - spin_lock_irqsave(&dev->spinlock, flags); - devpriv->command2_bits &= ~SWTRIG_BIT & ~HWTRIG_BIT & ~PRETRIG_BIT; - devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); - spin_unlock_irqrestore(&dev->spinlock, flags); - - /* disable interrupt generation and dma */ - devpriv->command3_bits = 0; - devpriv->write_byte(devpriv->command3_bits, dev->iobase + COMMAND3_REG); - - /* set gain and channel */ - devpriv->command1_bits = 0; - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); - devpriv->command1_bits |= thisboard->ai_range_code[range]; - /* munge channel bits for differential/scan disabled mode */ - if (CR_AREF(insn->chanspec) == AREF_DIFF) - chan *= 2; - devpriv->command1_bits |= ADC_CHAN_BITS(chan); - devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); - - /* setup command6 register for 1200 boards */ - if (thisboard->register_layout == labpc_1200_layout) { - /* reference inputs to ground or common? */ - if (CR_AREF(insn->chanspec) != AREF_GROUND) - devpriv->command6_bits |= ADC_COMMON_BIT; - else - devpriv->command6_bits &= ~ADC_COMMON_BIT; - /* bipolar or unipolar range? */ - if (thisboard->ai_range_is_unipolar[range]) - devpriv->command6_bits |= ADC_UNIP_BIT; - else - devpriv->command6_bits &= ~ADC_UNIP_BIT; - /* don't interrupt on fifo half full */ - devpriv->command6_bits &= ~ADC_FHF_INTR_EN_BIT; - /* don't enable interrupt on counter a1 terminal count? */ - devpriv->command6_bits &= ~A1_INTR_EN_BIT; - /* write to register */ - devpriv->write_byte(devpriv->command6_bits, - dev->iobase + COMMAND6_REG); - } - /* setup command4 register */ - devpriv->command4_bits = 0; - devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; - /* single-ended/differential */ - if (CR_AREF(insn->chanspec) == AREF_DIFF) - devpriv->command4_bits |= ADC_DIFF_BIT; - devpriv->write_byte(devpriv->command4_bits, dev->iobase + COMMAND4_REG); - - /* - * initialize pacer counter output to make sure it doesn't - * cause any problems - */ - devpriv->write_byte(INIT_A0_BITS, dev->iobase + COUNTER_A_CONTROL_REG); - - labpc_clear_adc_fifo(dev); - - for (n = 0; n < insn->n; n++) { - /* trigger conversion */ - devpriv->write_byte(0x1, dev->iobase + ADC_CONVERT_REG); - - for (i = 0; i < timeout; i++) { - if (devpriv->read_byte(dev->iobase + - STATUS1_REG) & DATA_AVAIL_BIT) - break; - udelay(1); - } - if (i == timeout) { - comedi_error(dev, "timeout"); - return -ETIME; - } - lsb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG); - msb = devpriv->read_byte(dev->iobase + ADC_FIFO_REG); - data[n] = (msb << 8) | lsb; - } - - return n; -} - -/* analog output insn */ -static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +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; @@ -1683,20 +1008,19 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, /* 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->command2_bits &= ~DAC_PACED_BIT(channel); - devpriv->write_byte(devpriv->command2_bits, dev->iobase + COMMAND2_REG); + devpriv->cmd2 &= ~CMD2_LDAC(channel); + devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG); spin_unlock_irqrestore(&dev->spinlock, flags); /* set range */ - if (thisboard->register_layout == labpc_1200_layout) { + if (board->is_labpc1200) { range = CR_RANGE(insn->chanspec); - if (range & AO_RANGE_IS_UNIPOLAR) - devpriv->command6_bits |= DAC_UNIP_BIT(channel); + if (comedi_range_is_unipolar(s, range)) + devpriv->cmd6 |= CMD6_DACUNI(channel); else - devpriv->command6_bits &= ~DAC_UNIP_BIT(channel); + devpriv->cmd6 &= ~CMD6_DACUNI(channel); /* write to register */ - devpriv->write_byte(devpriv->command6_bits, - dev->iobase + COMMAND6_REG); + devpriv->write_byte(devpriv->cmd6, dev->iobase + CMD6_REG); } /* send data */ lsb = data[0] & 0xff; @@ -1710,198 +1034,25 @@ static int labpc_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, return 1; } -/* analog output readback insn */ -static int labpc_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; - - return 1; -} - -static int labpc_calib_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[0] = devpriv->caldac[CR_CHAN(insn->chanspec)]; - - return 1; -} - -static int labpc_calib_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int channel = CR_CHAN(insn->chanspec); - - write_caldac(dev, channel, data[0]); - return 1; -} - -static int labpc_eeprom_read_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - data[0] = devpriv->eeprom_data[CR_CHAN(insn->chanspec)]; - - return 1; -} - -static int labpc_eeprom_write_insn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int labpc_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int channel = CR_CHAN(insn->chanspec); - int ret; + struct labpc_private *devpriv = dev->private; - /* only allow writes to user area of eeprom */ - if (channel < 16 || channel > 127) { - printk - ("eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)"); - return -EINVAL; - } - - ret = labpc_eeprom_write(dev, channel, data[0]); - if (ret < 0) - return ret; + data[0] = devpriv->ao_value[CR_CHAN(insn->chanspec)]; return 1; } -/* utility function that suggests a dma transfer size in bytes */ -static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd) -{ - unsigned int size; - unsigned int freq; - - if (cmd.convert_src == TRIG_TIMER) - freq = 1000000000 / cmd.convert_arg; - /* return some default value */ - else - freq = 0xffffffff; - - /* make buffer fill in no more than 1/3 second */ - size = (freq / 3) * sample_size; - - /* set a minimum and maximum size allowed */ - if (size > dma_buffer_size) - size = dma_buffer_size - dma_buffer_size % sample_size; - else if (size < sample_size) - size = sample_size; - - return size; -} - -/* figures out what counter values to use based on command */ -static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) -{ - /* 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; - - /* - * if both convert and scan triggers are TRIG_TIMER, then they - * both rely on counter b0 - */ - if (labpc_ai_convert_period(cmd) && labpc_ai_scan_period(cmd)) { - /* - * pick the lowest b0 divisor value we can (for maximum input - * clock speed on convert and scan counters) - */ - devpriv->divisor_b0 = (labpc_ai_scan_period(cmd) - 1) / - (LABPC_TIMER_BASE * 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 = LABPC_TIMER_BASE * 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 = - (labpc_ai_convert_period(cmd) + - (base_period / 2)) / base_period; - devpriv->divisor_b1 = - (labpc_ai_scan_period(cmd) + - (base_period / 2)) / base_period; - break; - case TRIG_ROUND_UP: - devpriv->divisor_a0 = - (labpc_ai_convert_period(cmd) + (base_period - - 1)) / base_period; - devpriv->divisor_b1 = - (labpc_ai_scan_period(cmd) + (base_period - - 1)) / base_period; - break; - case TRIG_ROUND_DOWN: - devpriv->divisor_a0 = - labpc_ai_convert_period(cmd) / base_period; - devpriv->divisor_b1 = - labpc_ai_scan_period(cmd) / 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, - base_period * devpriv->divisor_a0); - labpc_set_ai_scan_period(cmd, - base_period * devpriv->divisor_b1); - /* - * if only one TRIG_TIMER is used, we can employ the generic - * cascaded timing functions - */ - } else if (labpc_ai_scan_period(cmd)) { - unsigned int scan_period; - - scan_period = labpc_ai_scan_period(cmd); - /* - * calculate cascaded counter values - * that give desired scan timing - */ - i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE, - &(devpriv->divisor_b1), - &(devpriv->divisor_b0), - &scan_period, - cmd->flags & TRIG_ROUND_MASK); - labpc_set_ai_scan_period(cmd, scan_period); - } else if (labpc_ai_convert_period(cmd)) { - unsigned int convert_period; - - convert_period = labpc_ai_convert_period(cmd); - /* - * calculate cascaded counter values - * that give desired conversion timing - */ - i8253_cascade_ns_to_timer_2div(LABPC_TIMER_BASE, - &(devpriv->divisor_a0), - &(devpriv->divisor_b0), - &convert_period, - cmd->flags & TRIG_ROUND_MASK); - labpc_set_ai_convert_period(cmd, convert_period); - } -} - -static int labpc_dio_mem_callback(int dir, int port, int data, - unsigned long iobase) +static int labpc_8255_mmio(int dir, int port, int data, unsigned long iobase) { if (dir) { - writeb(data, (void *)(iobase + port)); + writeb(data, (void __iomem *)(iobase + port)); return 0; } else { - return readb((void *)(iobase + port)); + return readb((void __iomem *)(iobase + port)); } } @@ -1909,50 +1060,47 @@ static int labpc_dio_mem_callback(int dir, int port, int data, 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->command5_bits &= ~SCLOCK_BIT; + devpriv->cmd5 &= ~CMD5_SCLK; /* send bits most significant bit first */ if (value & (1 << (value_width - i))) - devpriv->command5_bits |= SDATA_BIT; + devpriv->cmd5 |= CMD5_SDATA; else - devpriv->command5_bits &= ~SDATA_BIT; + devpriv->cmd5 &= ~CMD5_SDATA; udelay(1); - devpriv->write_byte(devpriv->command5_bits, - dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); /* set clock to load bit */ - devpriv->command5_bits |= SCLOCK_BIT; + devpriv->cmd5 |= CMD5_SCLK; udelay(1); - devpriv->write_byte(devpriv->command5_bits, - dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + 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->command5_bits |= SCLOCK_BIT; + devpriv->cmd5 |= CMD5_SCLK; udelay(1); - devpriv->write_byte(devpriv->command5_bits, - dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); /* clear clock bit */ - devpriv->command5_bits &= ~SCLOCK_BIT; + devpriv->cmd5 &= ~CMD5_SCLK; udelay(1); - devpriv->write_byte(devpriv->command5_bits, - dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); /* read bits most significant bit first */ udelay(1); - devpriv->status2_bits = - devpriv->read_byte(dev->iobase + STATUS2_REG); - if (devpriv->status2_bits & EEPROM_OUT_BIT) + devpriv->stat2 = devpriv->read_byte(dev->iobase + STAT2_REG); + if (devpriv->stat2 & STAT2_PROMOUT) value |= 1 << (value_width - i); } @@ -1962,6 +1110,7 @@ static unsigned int labpc_serial_in(struct comedi_device *dev) 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; @@ -1969,12 +1118,12 @@ static unsigned int labpc_eeprom_read(struct comedi_device *dev, const int write_length = 8; /* enable read/write to eeprom */ - devpriv->command5_bits &= ~EEPROM_EN_BIT; + devpriv->cmd5 &= ~CMD5_EEPROMCS; udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT; + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); + devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); /* send read instruction */ labpc_serial_out(dev, read_instruction, write_length); @@ -1984,9 +1133,37 @@ static unsigned int labpc_eeprom_read(struct comedi_device *dev, value = labpc_serial_in(dev); /* disable read/write to eeprom */ - devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT; + devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(devpriv->cmd5, dev->iobase + 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(devpriv->cmd5, dev->iobase + CMD5_REG); + devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); + udelay(1); + devpriv->write_byte(devpriv->cmd5, dev->iobase + 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(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); return value; } @@ -1994,6 +1171,7 @@ static unsigned int labpc_eeprom_read(struct comedi_device *dev, 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 */ @@ -2015,80 +1193,54 @@ static int labpc_eeprom_write(struct comedi_device *dev, devpriv->eeprom_data[address] = value; /* enable read/write to eeprom */ - devpriv->command5_bits &= ~EEPROM_EN_BIT; + devpriv->cmd5 &= ~CMD5_EEPROMCS; udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT; + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); + devpriv->cmd5 |= (CMD5_EEPROMCS | CMD5_WRTPRT); udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); /* send write_enable instruction */ labpc_serial_out(dev, write_enable_instruction, write_length); - devpriv->command5_bits &= ~EEPROM_EN_BIT; + devpriv->cmd5 &= ~CMD5_EEPROMCS; udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); /* send write instruction */ - devpriv->command5_bits |= EEPROM_EN_BIT; + devpriv->cmd5 |= CMD5_EEPROMCS; udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + 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->command5_bits &= ~EEPROM_EN_BIT; + devpriv->cmd5 &= ~CMD5_EEPROMCS; udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); /* disable read/write to eeprom */ - devpriv->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT; + devpriv->cmd5 &= ~(CMD5_EEPROMCS | CMD5_WRTPRT); udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); return 0; } -static unsigned int labpc_eeprom_read_status(struct comedi_device *dev) -{ - 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->command5_bits &= ~EEPROM_EN_BIT; - udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - devpriv->command5_bits |= EEPROM_EN_BIT | EEPROM_WRITE_UNPROTECT_BIT; - udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_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->command5_bits &= ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT; - udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - - return value; -} - /* 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->command5_bits &= - ~CALDAC_LOAD_BIT & ~EEPROM_EN_BIT & ~EEPROM_WRITE_UNPROTECT_BIT; + devpriv->cmd5 &= ~(CMD5_CALDACLD | CMD5_EEPROMCS | CMD5_WRTPRT); udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); /* write 4 bit channel */ labpc_serial_out(dev, channel, 4); @@ -2096,68 +1248,268 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel, labpc_serial_out(dev, value, 8); /* set and clear caldac bit to load caldac value */ - devpriv->command5_bits |= CALDAC_LOAD_BIT; + devpriv->cmd5 |= CMD5_CALDACLD; udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); - devpriv->command5_bits &= ~CALDAC_LOAD_BIT; + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); + devpriv->cmd5 &= ~CMD5_CALDACLD; udelay(1); - devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); + devpriv->write_byte(devpriv->cmd5, dev->iobase + 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; } -#ifdef CONFIG_COMEDI_PCI -static int __devinit driver_labpc_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static int labpc_calib_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - return comedi_pci_auto_config(dev, driver_labpc.driver_name); + 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 void __devexit driver_labpc_pci_remove(struct pci_dev *dev) +static int labpc_eeprom_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - comedi_pci_auto_unconfig(dev); + 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 struct pci_driver driver_labpc_pci_driver = { - .id_table = labpc_pci_table, - .probe = &driver_labpc_pci_probe, - .remove = __devexit_p(&driver_labpc_pci_remove) -}; +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 (board->has_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(devpriv->cmd1, dev->iobase + CMD1_REG); + devpriv->write_byte(devpriv->cmd2, dev->iobase + CMD2_REG); + devpriv->write_byte(devpriv->cmd3, dev->iobase + CMD3_REG); + devpriv->write_byte(devpriv->cmd4, dev->iobase + CMD4_REG); + if (board->is_labpc1200) { + devpriv->write_byte(devpriv->cmd5, dev->iobase + CMD5_REG); + devpriv->write_byte(devpriv->cmd6, dev->iobase + 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(lsb, dev->iobase + DAC_LSB_REG(i)); + devpriv->write_byte(msb, dev->iobase + DAC_MSB_REG(i)); + } + } else { + s->type = COMEDI_SUBD_UNUSED; + } + + /* 8255 dio */ + s = &dev->subdevices[2]; + ret = subdev_8255_init(dev, s, + (board->has_mmio) ? labpc_8255_mmio : 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; -static int __init driver_labpc_init_module(void) + 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) { - int retval; + struct labpc_private *devpriv; + unsigned int irq = it->options[1]; + unsigned int dma_chan = it->options[2]; + int ret; - retval = comedi_driver_register(&driver_labpc); - if (retval < 0) - return retval; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - driver_labpc_pci_driver.name = (char *)driver_labpc.driver_name; - return pci_register_driver(&driver_labpc_pci_driver); + ret = comedi_request_region(dev, it->options[0], LABPC_SIZE); + if (ret) + return ret; + + ret = labpc_common_attach(dev, irq, 0); + if (ret) + return ret; + + if (dev->irq) + labpc_init_dma_chan(dev, dma_chan); + + return 0; } -static void __exit driver_labpc_cleanup_module(void) +static void labpc_detach(struct comedi_device *dev) { - pci_unregister_driver(&driver_labpc_pci_driver); - comedi_driver_unregister(&driver_labpc); + struct labpc_private *devpriv = dev->private; + + if (devpriv) + labpc_free_dma_chan(dev); + + comedi_legacy_detach(dev); } -module_init(driver_labpc_init_module); -module_exit(driver_labpc_cleanup_module); +static struct comedi_driver labpc_driver = { + .driver_name = "ni_labpc", + .module = THIS_MODULE, + .attach = labpc_attach, + .detach = labpc_detach, + .num_names = ARRAY_SIZE(labpc_boards), + .board_name = &labpc_boards[0].name, + .offset = sizeof(struct labpc_boardinfo), +}; +module_comedi_driver(labpc_driver); #else -static int __init driver_labpc_init_module(void) +static int __init labpc_common_init(void) { - return comedi_driver_register(&driver_labpc); + return 0; } +module_init(labpc_common_init); -static void __exit driver_labpc_cleanup_module(void) +static void __exit labpc_common_exit(void) { - comedi_driver_unregister(&driver_labpc); } - -module_init(driver_labpc_init_module); -module_exit(driver_labpc_cleanup_module); +module_exit(labpc_common_exit); #endif - MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h index 422cee58a96..486589fa6fd 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.h +++ b/drivers/staging/comedi/drivers/ni_labpc.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _NI_LABPC_H @@ -27,48 +22,35 @@ #define EEPROM_SIZE 256 /* 256 byte eeprom */ #define NUM_AO_CHAN 2 /* boards have two analog output channels */ -enum labpc_bustype { isa_bustype, pci_bustype, pcmcia_bustype }; -enum labpc_register_layout { labpc_plus_layout, labpc_1200_layout }; enum transfer_type { fifo_not_empty_transfer, fifo_half_full_transfer, isa_dma_transfer }; -struct labpc_board_struct { +struct labpc_boardinfo { const char *name; - int device_id; /* device id for pci and pcmcia boards */ - int ai_speed; /* maximum input speed in nanoseconds */ - enum labpc_bustype bustype; /* ISA/PCI/etc. */ - - /* 1200 has extra registers compared to pc+ */ - enum labpc_register_layout register_layout; - int has_ao; /* has analog output true/false */ - const struct comedi_lrange *ai_range_table; - const int *ai_range_code; - const int *ai_range_is_unipolar; - - /* board can auto scan up in ai channels, not just down */ - unsigned ai_scan_up:1; - - /* uses memory mapped io instead of ioports */ - unsigned memory_mapped_io:1; + int ai_speed; /* maximum input speed in ns */ + unsigned ai_scan_up:1; /* can auto scan up in ai channels */ + unsigned has_ao:1; /* has analog outputs */ + unsigned is_labpc1200:1; /* has extra regs compared to pc+ */ + unsigned has_mmio:1; /* uses memory mapped io */ }; struct labpc_private { struct mite_struct *mite; /* for mite chip on pci-1200 */ /* number of data points left to be taken */ - volatile unsigned long long count; + unsigned long long count; /* software copy of analog output values */ unsigned int ao_value[NUM_AO_CHAN]; /* software copys of bits written to command registers */ - volatile unsigned int command1_bits; - volatile unsigned int command2_bits; - volatile unsigned int command3_bits; - volatile unsigned int command4_bits; - volatile unsigned int command5_bits; - volatile unsigned int command6_bits; + unsigned int cmd1; + unsigned int cmd2; + unsigned int cmd3; + unsigned int cmd4; + unsigned int cmd5; + unsigned int cmd6; /* store last read of board status registers */ - volatile unsigned int status1_bits; - volatile unsigned int status2_bits; + unsigned int stat1; + unsigned int stat2; /* * value to load into board's counter a0 (conversion pacing) for timed * conversions @@ -85,6 +67,7 @@ struct labpc_private { unsigned int divisor_b1; unsigned int dma_chan; /* dma channel to use */ u16 *dma_buffer; /* buffer ai will dma into */ + phys_addr_t dma_addr; /* transfer size in bytes for current transfer */ unsigned int dma_transfer_size; /* we are using dma/fifo-half-full/etc. */ @@ -101,12 +84,7 @@ struct labpc_private { void (*write_byte) (unsigned int byte, unsigned long address); }; -int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, - unsigned int irq, unsigned int dma); -int labpc_common_detach(struct comedi_device *dev); - -extern const int labpc_1200_is_unipolar[]; -extern const int labpc_1200_ai_gain_bits[]; -extern const struct comedi_lrange range_labpc_1200_ai; +int labpc_common_attach(struct comedi_device *dev, + unsigned int irq, unsigned long isr_flags); #endif /* _NI_LABPC_H */ diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index 832a5178b63..0a8b3223f74 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -18,12 +18,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -************************************************************************ */ /* Driver: ni_labpc_cs @@ -59,12 +53,10 @@ NI manuals: */ -#undef LABPC_DEBUG /* debugging messages */ - +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/slab.h> #include "8253.h" #include "8255.h" @@ -75,246 +67,69 @@ NI manuals: #include <pcmcia/cisreg.h> #include <pcmcia/ds.h> -static struct pcmcia_device *pcmcia_cur_dev; - -static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it); - -static const struct labpc_board_struct labpc_cs_boards[] = { - { - .name = "daqcard-1200", - .device_id = 0x103, /* 0x10b is manufacturer id, - 0x103 is device id */ - .ai_speed = 10000, - .bustype = pcmcia_bustype, - .register_layout = labpc_1200_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, - .ai_range_is_unipolar = labpc_1200_is_unipolar, - .ai_scan_up = 0, - .memory_mapped_io = 0, - }, - /* duplicate entry, to support using alternate name */ +static const struct labpc_boardinfo labpc_cs_boards[] = { { - .name = "ni_labpc_cs", - .device_id = 0x103, - .ai_speed = 10000, - .bustype = pcmcia_bustype, - .register_layout = labpc_1200_layout, - .has_ao = 1, - .ai_range_table = &range_labpc_1200_ai, - .ai_range_code = labpc_1200_ai_gain_bits, - .ai_range_is_unipolar = labpc_1200_is_unipolar, - .ai_scan_up = 0, - .memory_mapped_io = 0, - }, -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct labpc_board_struct *)dev->board_ptr) - -static struct comedi_driver driver_labpc_cs = { - .driver_name = "ni_labpc_cs", - .module = THIS_MODULE, - .attach = &labpc_attach, - .detach = &labpc_common_detach, - .num_names = ARRAY_SIZE(labpc_cs_boards), - .board_name = &labpc_cs_boards[0].name, - .offset = sizeof(struct labpc_board_struct), + .name = "daqcard-1200", + .ai_speed = 10000, + .has_ao = 1, + .is_labpc1200 = 1, + }, }; -static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int labpc_auto_attach(struct comedi_device *dev, + unsigned long context) { - unsigned long iobase = 0; - unsigned int irq = 0; - struct pcmcia_device *link; + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + struct labpc_private *devpriv; + int ret; - /* allocate and initialize dev->private */ - if (alloc_private(dev, sizeof(struct labpc_private)) < 0) - return -ENOMEM; + /* The ni_labpc driver needs the board_ptr */ + dev->board_ptr = &labpc_cs_boards[0]; + + link->config_flags |= CONF_AUTO_SET_IO | + CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; + dev->iobase = link->resource[0]->start; - /* get base address, irq etc. based on bustype */ - switch (thisboard->bustype) { - case pcmcia_bustype: - link = pcmcia_cur_dev; /* XXX hack */ - if (!link) - return -EIO; - iobase = link->resource[0]->start; - irq = link->irq; - break; - default: - printk("bug! couldn't determine board type\n"); + if (!link->irq) return -EINVAL; - break; - } - return labpc_common_attach(dev, iobase, irq, 0); -} -static void labpc_config(struct pcmcia_device *link); -static void labpc_release(struct pcmcia_device *link); -static int labpc_cs_suspend(struct pcmcia_device *p_dev); -static int labpc_cs_resume(struct pcmcia_device *p_dev); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; -static int labpc_cs_attach(struct pcmcia_device *); -static void labpc_cs_detach(struct pcmcia_device *); + return labpc_common_attach(dev, link->irq, IRQF_SHARED); +} -struct local_info_t { - struct pcmcia_device *link; - int stop; - struct bus_operations *bus; +static struct comedi_driver driver_labpc_cs = { + .driver_name = "ni_labpc_cs", + .module = THIS_MODULE, + .auto_attach = labpc_auto_attach, + .detach = comedi_pcmcia_disable, }; static int labpc_cs_attach(struct pcmcia_device *link) { - struct local_info_t *local; - - dev_dbg(&link->dev, "labpc_cs_attach()\n"); - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; - local->link = link; - link->priv = local; - - pcmcia_cur_dev = link; - - labpc_config(link); - - return 0; -} /* labpc_cs_attach */ - -static void labpc_cs_detach(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "labpc_cs_detach\n"); - - /* - If the device is currently configured and active, we won't - actually delete it yet. Instead, it is marked so that when - the release() function is called, that will trigger a proper - detach(). - */ - ((struct local_info_t *)link->priv)->stop = 1; - labpc_release(link); - - /* This points to the parent local_info_t struct (may be null) */ - kfree(link->priv); - -} /* labpc_cs_detach */ - -static int labpc_pcmcia_config_loop(struct pcmcia_device *p_dev, - void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); + return comedi_pcmcia_auto_config(link, &driver_labpc_cs); } - -static void labpc_config(struct pcmcia_device *link) -{ - int ret; - - dev_dbg(&link->dev, "labpc_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_ENABLE_PULSE_IRQ | - CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, labpc_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } - - if (!link->irq) - goto failed; - - ret = pcmcia_enable_device(link); - if (ret) - goto failed; - - return; - -failed: - labpc_release(link); - -} /* labpc_config */ - -static void labpc_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "labpc_release\n"); - - pcmcia_disable_device(link); -} /* labpc_release */ - -static int labpc_cs_suspend(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - /* Mark the device as stopped, to block IO until later */ - local->stop = 1; - return 0; -} /* labpc_cs_suspend */ - -static int labpc_cs_resume(struct pcmcia_device *link) -{ - struct local_info_t *local = link->priv; - - local->stop = 0; - return 0; -} /* labpc_cs_resume */ - static const struct pcmcia_device_id labpc_cs_ids[] = { - /* N.B. These IDs should match those in labpc_cs_boards (ni_labpc.c) */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0103), /* daqcard-1200 */ PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, labpc_cs_ids); -MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); -MODULE_DESCRIPTION("Comedi driver for National Instruments Lab-PC"); -MODULE_LICENSE("GPL"); -struct pcmcia_driver labpc_cs_driver = { - .probe = labpc_cs_attach, - .remove = labpc_cs_detach, - .suspend = labpc_cs_suspend, - .resume = labpc_cs_resume, - .id_table = labpc_cs_ids, - .owner = THIS_MODULE, - .name = "daqcard-1200", +static struct pcmcia_driver labpc_cs_driver = { + .name = "daqcard-1200", + .owner = THIS_MODULE, + .id_table = labpc_cs_ids, + .probe = labpc_cs_attach, + .remove = comedi_pcmcia_auto_unconfig, }; +module_comedi_pcmcia_driver(driver_labpc_cs, labpc_cs_driver); -static int __init init_labpc_cs(void) -{ - pcmcia_register_driver(&labpc_cs_driver); - return 0; -} - -static void __exit exit_labpc_cs(void) -{ - pcmcia_unregister_driver(&labpc_cs_driver); -} - -int __init labpc_init_module(void) -{ - int ret; - - ret = init_labpc_cs(); - if (ret < 0) - return ret; - - return comedi_driver_register(&driver_labpc_cs); -} - -void __exit labpc_exit_module(void) -{ - exit_labpc_cs(); - comedi_driver_unregister(&driver_labpc_cs); -} - -module_init(labpc_init_module); -module_exit(labpc_exit_module); +MODULE_DESCRIPTION("Comedi driver for National Instruments Lab-PC"); +MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c new file mode 100644 index 00000000000..d9f25fdbb72 --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c @@ -0,0 +1,227 @@ +/* + * comedi/drivers/ni_labpc_isadma.c + * ISA DMA support for National Instruments Lab-PC series boards and + * compatibles. + * + * Extracted from ni_labpc.c: + * 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/slab.h> +#include "../comedidev.h" + +#include <asm/dma.h> + +#include "comedi_fc.h" +#include "ni_labpc.h" +#include "ni_labpc_regs.h" +#include "ni_labpc_isadma.h" + +/* size in bytes of dma buffer */ +static const int dma_buffer_size = 0xff00; +/* 2 bytes per sample */ +static const int sample_size = 2; + +/* utility function that suggests a dma transfer size in bytes */ +static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd) +{ + unsigned int size; + unsigned int freq; + + if (cmd->convert_src == TRIG_TIMER) + freq = 1000000000 / cmd->convert_arg; + else + /* return some default value */ + freq = 0xffffffff; + + /* make buffer fill in no more than 1/3 second */ + size = (freq / 3) * sample_size; + + /* set a minimum and maximum size allowed */ + if (size > dma_buffer_size) + size = dma_buffer_size - dma_buffer_size % sample_size; + else if (size < sample_size) + size = sample_size; + + return size; +} + +void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct labpc_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned long irq_flags; + + irq_flags = claim_dma_lock(); + disable_dma(devpriv->dma_chan); + /* clear flip-flop to make sure 2-byte registers for + * count and address get set correctly */ + clear_dma_ff(devpriv->dma_chan); + set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); + /* set appropriate size of transfer */ + devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd); + if (cmd->stop_src == TRIG_COUNT && + devpriv->count * sample_size < devpriv->dma_transfer_size) + devpriv->dma_transfer_size = devpriv->count * sample_size; + set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); + enable_dma(devpriv->dma_chan); + release_dma_lock(irq_flags); + /* set CMD3 bits for caller to enable DMA and interrupt */ + devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN); +} +EXPORT_SYMBOL_GPL(labpc_setup_dma); + +void labpc_drain_dma(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + int status; + unsigned long flags; + unsigned int max_points, num_points, residue, leftover; + int i; + + status = devpriv->stat1; + + flags = claim_dma_lock(); + disable_dma(devpriv->dma_chan); + /* clear flip-flop to make sure 2-byte registers for + * count and address get set correctly */ + clear_dma_ff(devpriv->dma_chan); + + /* figure out how many points to read */ + max_points = devpriv->dma_transfer_size / sample_size; + /* residue is the number of points left to be done on the dma + * transfer. It should always be zero at this point unless + * the stop_src is set to external triggering. + */ + residue = get_dma_residue(devpriv->dma_chan) / sample_size; + num_points = max_points - residue; + if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_points) + num_points = devpriv->count; + + /* figure out how many points will be stored next time */ + leftover = 0; + if (cmd->stop_src != TRIG_COUNT) { + leftover = devpriv->dma_transfer_size / sample_size; + } else if (devpriv->count > num_points) { + leftover = devpriv->count - num_points; + if (leftover > max_points) + leftover = max_points; + } + + /* write data to comedi buffer */ + for (i = 0; i < num_points; i++) + cfc_write_to_buffer(s, devpriv->dma_buffer[i]); + + if (cmd->stop_src == TRIG_COUNT) + devpriv->count -= num_points; + + /* set address and count for next transfer */ + set_dma_addr(devpriv->dma_chan, devpriv->dma_addr); + set_dma_count(devpriv->dma_chan, leftover * sample_size); + release_dma_lock(flags); + + async->events |= COMEDI_CB_BLOCK; +} +EXPORT_SYMBOL_GPL(labpc_drain_dma); + +static void handle_isa_dma(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + labpc_drain_dma(dev); + + enable_dma(devpriv->dma_chan); + + /* clear dma tc interrupt */ + devpriv->write_byte(0x1, dev->iobase + DMATC_CLEAR_REG); +} + +void labpc_handle_dma_status(struct comedi_device *dev) +{ + const struct labpc_boardinfo *board = comedi_board(dev); + struct labpc_private *devpriv = dev->private; + + /* + * if a dma terminal count of external stop trigger + * has occurred + */ + if (devpriv->stat1 & STAT1_GATA0 || + (board->is_labpc1200 && devpriv->stat2 & STAT2_OUTA1)) + handle_isa_dma(dev); +} +EXPORT_SYMBOL_GPL(labpc_handle_dma_status); + +int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan) +{ + struct labpc_private *devpriv = dev->private; + void *dma_buffer; + unsigned long dma_flags; + int ret; + + if (dma_chan != 1 && dma_chan != 3) + return -EINVAL; + + dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA); + if (!dma_buffer) + return -ENOMEM; + + ret = request_dma(dma_chan, dev->board_name); + if (ret) { + kfree(dma_buffer); + return ret; + } + + devpriv->dma_buffer = dma_buffer; + devpriv->dma_chan = dma_chan; + devpriv->dma_addr = virt_to_bus(devpriv->dma_buffer); + + dma_flags = claim_dma_lock(); + disable_dma(devpriv->dma_chan); + set_dma_mode(devpriv->dma_chan, DMA_MODE_READ); + release_dma_lock(dma_flags); + + return 0; +} +EXPORT_SYMBOL_GPL(labpc_init_dma_chan); + +void labpc_free_dma_chan(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + kfree(devpriv->dma_buffer); + devpriv->dma_buffer = NULL; + if (devpriv->dma_chan) { + free_dma(devpriv->dma_chan); + devpriv->dma_chan = 0; + } +} +EXPORT_SYMBOL_GPL(labpc_free_dma_chan); + +static int __init ni_labpc_isadma_init_module(void) +{ + return 0; +} +module_init(ni_labpc_isadma_init_module); + +static void __exit ni_labpc_isadma_cleanup_module(void) +{ +} +module_exit(ni_labpc_isadma_cleanup_module); + +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_DESCRIPTION("Comedi NI Lab-PC ISA DMA support"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.h b/drivers/staging/comedi/drivers/ni_labpc_isadma.h new file mode 100644 index 00000000000..771af4bd5a7 --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.h @@ -0,0 +1,57 @@ +/* + * ni_labpc ISA DMA support. +*/ + +#ifndef _NI_LABPC_ISADMA_H +#define _NI_LABPC_ISADMA_H + +#define NI_LABPC_HAVE_ISA_DMA IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA) + +#if NI_LABPC_HAVE_ISA_DMA + +static inline bool labpc_have_dma_chan(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + return (bool)devpriv->dma_chan; +} + +int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan); +void labpc_free_dma_chan(struct comedi_device *dev); +void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s); +void labpc_drain_dma(struct comedi_device *dev); +void labpc_handle_dma_status(struct comedi_device *dev); + +#else + +static inline bool labpc_have_dma_chan(struct comedi_device *dev) +{ + return false; +} + +static inline int labpc_init_dma_chan(struct comedi_device *dev, + unsigned int dma_chan) +{ + return -ENOTSUPP; +} + +static inline void labpc_free_dma_chan(struct comedi_device *dev) +{ +} + +static inline void labpc_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ +} + +static inline void labpc_drain_dma(struct comedi_device *dev) +{ +} + +static inline void labpc_handle_dma_status(struct comedi_device *dev) +{ +} + +#endif + +#endif /* _NI_LABPC_ISADMA_H */ diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c new file mode 100644 index 00000000000..73959706829 --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c @@ -0,0 +1,133 @@ +/* + * comedi/drivers/ni_labpc_pci.c + * Driver for National Instruments Lab-PC PCI-1200 + * Copyright (C) 2001, 2002, 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. + */ + +/* + * Driver: ni_labpc_pci + * Description: National Instruments Lab-PC PCI-1200 + * Devices: (National Instruments) PCI-1200 [ni_pci-1200] + * Author: Frank Mori Hess <fmhess@users.sourceforge.net> + * Status: works + * + * This is the PCI-specific support split off from the ni_labpc driver. + * + * Configuration Options: not applicable, uses PCI auto config + * + * NI manuals: + * 340914a (pci-1200) + */ + +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/pci.h> + +#include "../comedidev.h" + +#include "mite.h" +#include "ni_labpc.h" + +enum labpc_pci_boardid { + BOARD_NI_PCI1200, +}; + +static const struct labpc_boardinfo labpc_pci_boards[] = { + [BOARD_NI_PCI1200] = { + .name = "ni_pci-1200", + .ai_speed = 10000, + .ai_scan_up = 1, + .has_ao = 1, + .is_labpc1200 = 1, + .has_mmio = 1, + }, +}; + +static int labpc_pci_auto_attach(struct comedi_device *dev, + unsigned long context) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct labpc_boardinfo *board = NULL; + struct labpc_private *devpriv; + int ret; + + if (context < ARRAY_SIZE(labpc_pci_boards)) + board = &labpc_pci_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; + ret = mite_setup(devpriv->mite); + if (ret < 0) + return ret; + dev->iobase = (unsigned long)devpriv->mite->daq_io_addr; + + return labpc_common_attach(dev, mite_irq(devpriv->mite), IRQF_SHARED); +} + +static void labpc_pci_detach(struct comedi_device *dev) +{ + struct labpc_private *devpriv = dev->private; + + if (devpriv && devpriv->mite) { + mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); + } + 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, +}; + +static const struct pci_device_id labpc_pci_table[] = { + { PCI_VDEVICE(NI, 0x161), BOARD_NI_PCI1200 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, labpc_pci_table); + +static int labpc_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &labpc_pci_comedi_driver, + id->driver_data); +} + +static struct pci_driver labpc_pci_driver = { + .name = "labpc_pci", + .id_table = labpc_pci_table, + .probe = labpc_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(labpc_pci_comedi_driver, labpc_pci_driver); + +MODULE_DESCRIPTION("Comedi: National Instruments Lab-PC PCI-1200 driver"); +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_labpc_regs.h b/drivers/staging/comedi/drivers/ni_labpc_regs.h new file mode 100644 index 00000000000..2a274a3e4e7 --- /dev/null +++ b/drivers/staging/comedi/drivers/ni_labpc_regs.h @@ -0,0 +1,75 @@ +/* + * ni_labpc register definitions. +*/ + +#ifndef _NI_LABPC_REGS_H +#define _NI_LABPC_REGS_H + +/* + * Register map (all registers are 8-bit) + */ +#define STAT1_REG 0x00 /* R: Status 1 reg */ +#define STAT1_DAVAIL (1 << 0) +#define STAT1_OVERRUN (1 << 1) +#define STAT1_OVERFLOW (1 << 2) +#define STAT1_CNTINT (1 << 3) +#define STAT1_GATA0 (1 << 5) +#define STAT1_EXTGATA0 (1 << 6) +#define CMD1_REG 0x00 /* W: Command 1 reg */ +#define CMD1_MA(x) (((x) & 0x7) << 0) +#define CMD1_TWOSCMP (1 << 3) +#define CMD1_GAIN(x) (((x) & 0x7) << 4) +#define CMD1_SCANEN (1 << 7) +#define CMD2_REG 0x01 /* W: Command 2 reg */ +#define CMD2_PRETRIG (1 << 0) +#define CMD2_HWTRIG (1 << 1) +#define CMD2_SWTRIG (1 << 2) +#define CMD2_TBSEL (1 << 3) +#define CMD2_2SDAC0 (1 << 4) +#define CMD2_2SDAC1 (1 << 5) +#define CMD2_LDAC(x) (1 << (6 + (x))) +#define CMD3_REG 0x02 /* W: Command 3 reg */ +#define CMD3_DMAEN (1 << 0) +#define CMD3_DIOINTEN (1 << 1) +#define CMD3_DMATCINTEN (1 << 2) +#define CMD3_CNTINTEN (1 << 3) +#define CMD3_ERRINTEN (1 << 4) +#define CMD3_FIFOINTEN (1 << 5) +#define ADC_START_CONVERT_REG 0x03 /* W: Start Convert reg */ +#define DAC_LSB_REG(x) (0x04 + 2 * (x)) /* W: DAC0/1 LSB reg */ +#define DAC_MSB_REG(x) (0x05 + 2 * (x)) /* W: DAC0/1 MSB reg */ +#define ADC_FIFO_CLEAR_REG 0x08 /* W: A/D FIFO Clear reg */ +#define ADC_FIFO_REG 0x0a /* R: A/D FIFO reg */ +#define DMATC_CLEAR_REG 0x0a /* W: DMA Interrupt Clear reg */ +#define TIMER_CLEAR_REG 0x0c /* W: Timer Interrupt Clear reg */ +#define CMD6_REG 0x0e /* W: Command 6 reg */ +#define CMD6_NRSE (1 << 0) +#define CMD6_ADCUNI (1 << 1) +#define CMD6_DACUNI(x) (1 << (2 + (x))) +#define CMD6_HFINTEN (1 << 5) +#define CMD6_DQINTEN (1 << 6) +#define CMD6_SCANUP (1 << 7) +#define CMD4_REG 0x0f /* W: Command 3 reg */ +#define CMD4_INTSCAN (1 << 0) +#define CMD4_EOIRCV (1 << 1) +#define CMD4_ECLKDRV (1 << 2) +#define CMD4_SEDIFF (1 << 3) +#define CMD4_ECLKRCV (1 << 4) +#define DIO_BASE_REG 0x10 /* R/W: 8255 DIO base reg */ +#define COUNTER_A_BASE_REG 0x14 /* R/W: 8253 Counter A base reg */ +#define COUNTER_B_BASE_REG 0x18 /* R/W: 8253 Counter B base reg */ +#define CMD5_REG 0x1c /* W: Command 5 reg */ +#define CMD5_WRTPRT (1 << 2) +#define CMD5_DITHEREN (1 << 3) +#define CMD5_CALDACLD (1 << 4) +#define CMD5_SCLK (1 << 5) +#define CMD5_SDATA (1 << 6) +#define CMD5_EEPROMCS (1 << 7) +#define STAT2_REG 0x1d /* R: Status 2 reg */ +#define STAT2_PROMOUT (1 << 0) +#define STAT2_OUTA1 (1 << 1) +#define STAT2_FIFONHF (1 << 2) +#define INTERVAL_COUNT_REG 0x1e /* W: Interval Counter Data reg */ +#define INTERVAL_STROBE_REG 0x1f /* W: Interval Counter Strobe reg */ + +#endif /* _NI_LABPC_REGS_H */ diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index fd232bc5f87..7ffdcc07ef9 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -15,11 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* @@ -57,20 +52,13 @@ fully tested as yet. Terry Barnaby, BEAM Ltd. */ -/* #define DEBUG_INTERRUPT */ -/* #define DEBUG_STATUS_A */ -/* #define DEBUG_STATUS_B */ - #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/delay.h> #include "8255.h" #include "mite.h" #include "comedi_fc.h" -#ifndef MDPRINTK -#define MDPRINTK(format, args...) -#endif - /* A timeout count */ #define NI_TIMEOUT 1000 static const unsigned old_RTSI_clock_channel = 7; @@ -90,116 +78,109 @@ static const short ni_gainlkup[][16] = { [ai_gain_6143] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, }; -static const struct comedi_lrange range_ni_E_ai = { 16, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, 2.5), - RANGE(-1, 1), - RANGE(-0.5, 0.5), - RANGE(-0.25, 0.25), - RANGE(-0.1, 0.1), - RANGE(-0.05, 0.05), - RANGE(0, 20), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2), - RANGE(0, 1), - RANGE(0, 0.5), - RANGE(0, 0.2), - RANGE(0, 0.1), - } -}; - -static const struct comedi_lrange range_ni_E_ai_limited = { 8, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-1, 1), - RANGE(-0.1, - 0.1), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 1), - RANGE(0, 0.1), - } +static const struct comedi_lrange range_ni_E_ai = { + 16, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.25), + BIP_RANGE(0.1), + BIP_RANGE(0.05), + UNI_RANGE(20), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } }; -static const struct comedi_lrange range_ni_E_ai_limited14 = { 14, { - RANGE(-10, - 10), - RANGE(-5, 5), - RANGE(-2, 2), - RANGE(-1, 1), - RANGE(-0.5, - 0.5), - RANGE(-0.2, - 0.2), - RANGE(-0.1, - 0.1), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2), - RANGE(0, 1), - RANGE(0, - 0.5), - RANGE(0, - 0.2), - RANGE(0, - 0.1), - } +static const struct comedi_lrange range_ni_E_ai_limited = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(1), + BIP_RANGE(0.1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(1), + UNI_RANGE(0.1) + } }; -static const struct comedi_lrange range_ni_E_ai_bipolar4 = { 4, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-0.5, - 0.5), - RANGE(-0.05, - 0.05), - } +static const struct comedi_lrange range_ni_E_ai_limited14 = { + 14, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.2), + BIP_RANGE(0.1), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2), + UNI_RANGE(1), + UNI_RANGE(0.5), + UNI_RANGE(0.2), + UNI_RANGE(0.1) + } }; -static const struct comedi_lrange range_ni_E_ai_611x = { 8, { - RANGE(-50, 50), - RANGE(-20, 20), - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2, 2), - RANGE(-1, 1), - RANGE(-0.5, 0.5), - RANGE(-0.2, 0.2), - } +static const struct comedi_lrange range_ni_E_ai_bipolar4 = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05) + } }; -static const struct comedi_lrange range_ni_M_ai_622x = { 4, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-1, 1), - RANGE(-0.2, 0.2), - } +static const struct comedi_lrange range_ni_E_ai_611x = { + 8, { + BIP_RANGE(50), + BIP_RANGE(20), + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.2) + } }; -static const struct comedi_lrange range_ni_M_ai_628x = { 7, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2, 2), - RANGE(-1, 1), - RANGE(-0.5, 0.5), - RANGE(-0.2, 0.2), - RANGE(-0.1, 0.1), - } +static const struct comedi_lrange range_ni_M_ai_622x = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(1), + BIP_RANGE(0.2) + } }; -static const struct comedi_lrange range_ni_S_ai_6143 = { 1, { - RANGE(-5, +5), - } +static const struct comedi_lrange range_ni_M_ai_628x = { + 7, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + BIP_RANGE(0.5), + BIP_RANGE(0.2), + BIP_RANGE(0.1) + } }; -static const struct comedi_lrange range_ni_E_ao_ext = { 4, { - RANGE(-10, 10), - RANGE(0, 10), - RANGE_ext(-1, 1), - RANGE_ext(0, 1), - } +static const struct comedi_lrange range_ni_E_ao_ext = { + 4, { + BIP_RANGE(10), + UNI_RANGE(10), + RANGE_ext(-1, 1), + RANGE_ext(0, 1) + } }; static const struct comedi_lrange *const ni_range_lkup[] = { @@ -210,7 +191,7 @@ static const struct comedi_lrange *const ni_range_lkup[] = { [ai_gain_611x] = &range_ni_E_ai_611x, [ai_gain_622x] = &range_ni_M_ai_622x, [ai_gain_628x] = &range_ni_M_ai_628x, - [ai_gain_6143] = &range_ni_S_ai_6143 + [ai_gain_6143] = &range_bipolar5 }; static int ni_dio_insn_config(struct comedi_device *dev, @@ -275,18 +256,6 @@ static int ni_rtsi_insn_config(struct comedi_device *dev, static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_read_eeprom(struct comedi_device *dev, int addr); -#ifdef DEBUG_STATUS_A -static void ni_mio_print_status_a(int status); -#else -#define ni_mio_print_status_a(a) -#endif -#ifdef DEBUG_STATUS_B -static void ni_mio_print_status_b(int status); -#else -#define ni_mio_print_status_b(a) -#endif - -static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s); #ifndef PCIDMA static void ni_handle_fifo_half_full(struct comedi_device *dev); static int ni_ao_fifo_half_empty(struct comedi_device *dev, @@ -302,24 +271,12 @@ static void shutdown_ai_command(struct comedi_device *dev); static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s); - static int ni_8255_callback(int dir, int port, int data, unsigned long arg); -static int ni_gpct_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ni_gpct_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ni_gpct_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); +#ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int ni_gpct_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int ni_gpct_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); +static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s); +#endif static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index); @@ -329,10 +286,6 @@ static int cs5529_do_conversion(struct comedi_device *dev, static int cs5529_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -#ifdef NI_CS5529_DEBUG -static unsigned int cs5529_config_read(struct comedi_device *dev, - unsigned int reg_select_bits); -#endif static void cs5529_config_write(struct comedi_device *dev, unsigned int value, unsigned int reg_select_bits); @@ -410,6 +363,7 @@ static void get_last_sample_6143(struct comedi_device *dev); static inline void ni_set_bitfield(struct comedi_device *dev, int reg, unsigned bit_mask, unsigned bit_values) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); @@ -493,11 +447,10 @@ static inline void ni_set_gpct_dma_channel(struct comedi_device *dev, { unsigned bitfield; - if (mite_channel >= 0) { + if (mite_channel >= 0) bitfield = GPCT_DMA_Select_Bits(gpct_index, mite_channel); - } else { + else bitfield = 0; - } ni_set_bitfield(dev, G0_G1_Select, GPCT_DMA_Select_Mask(gpct_index), bitfield); } @@ -506,6 +459,7 @@ static inline void ni_set_gpct_dma_channel(struct comedi_device *dev, static inline void ni_set_cdo_dma_channel(struct comedi_device *dev, int mite_channel) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->soft_reg_copy_lock, flags); @@ -525,6 +479,7 @@ static inline void ni_set_cdo_dma_channel(struct comedi_device *dev, static int ni_request_ai_mite_channel(struct comedi_device *dev) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -545,6 +500,7 @@ static int ni_request_ai_mite_channel(struct comedi_device *dev) static int ni_request_ao_mite_channel(struct comedi_device *dev) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -567,6 +523,7 @@ static int ni_request_gpct_mite_channel(struct comedi_device *dev, unsigned gpct_index, enum comedi_io_direction direction) { + struct ni_private *devpriv = dev->private; unsigned long flags; struct mite_channel *mite_chan; @@ -595,6 +552,7 @@ static int ni_request_gpct_mite_channel(struct comedi_device *dev, static int ni_request_cdo_mite_channel(struct comedi_device *dev) { #ifdef PCIDMA + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -617,6 +575,7 @@ static int ni_request_cdo_mite_channel(struct comedi_device *dev) static void ni_release_ai_mite_channel(struct comedi_device *dev) { #ifdef PCIDMA + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -632,6 +591,7 @@ static void ni_release_ai_mite_channel(struct comedi_device *dev) static void ni_release_ao_mite_channel(struct comedi_device *dev) { #ifdef PCIDMA + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -644,10 +604,11 @@ static void ni_release_ao_mite_channel(struct comedi_device *dev) #endif /* PCIDMA */ } -void ni_release_gpct_mite_channel(struct comedi_device *dev, - unsigned gpct_index) -{ #ifdef PCIDMA +static void ni_release_gpct_mite_channel(struct comedi_device *dev, + unsigned gpct_index) +{ + struct ni_private *devpriv = dev->private; unsigned long flags; BUG_ON(gpct_index >= NUM_GPCT); @@ -663,12 +624,13 @@ void ni_release_gpct_mite_channel(struct comedi_device *dev, mite_release_channel(mite_chan); } spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); -#endif /* PCIDMA */ } +#endif /* PCIDMA */ static void ni_release_cdo_mite_channel(struct comedi_device *dev) { #ifdef PCIDMA + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -686,7 +648,10 @@ static void ni_release_cdo_mite_channel(struct comedi_device *dev) static void ni_e_series_enable_second_irq(struct comedi_device *dev, unsigned gpct_index, short enable) { - if (boardtype.reg_type & ni_reg_m_series_mask) + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + + if (board->reg_type & ni_reg_m_series_mask) return; switch (gpct_index) { case 0: @@ -716,14 +681,27 @@ static void ni_e_series_enable_second_irq(struct comedi_device *dev, static void ni_clear_ai_fifo(struct comedi_device *dev) { - if (boardtype.reg_type == ni_reg_6143) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + static const int timeout = 10000; + int i; + + if (board->reg_type == ni_reg_6143) { /* Flush the 6143 data FIFO */ ni_writel(0x10, AIFIFO_Control_6143); /* Flush fifo */ ni_writel(0x00, AIFIFO_Control_6143); /* Flush fifo */ - while (ni_readl(AIFIFO_Status_6143) & 0x10) ; /* Wait for complete */ + /* Wait for complete */ + for (i = 0; i < timeout; i++) { + if (!(ni_readl(AIFIFO_Status_6143) & 0x10)) + break; + udelay(1); + } + if (i == timeout) { + comedi_error(dev, "FIFO flush timeout."); + } } else { devpriv->stc_writew(dev, 1, ADC_FIFO_Clear); - if (boardtype.reg_type == ni_reg_625x) { + if (board->reg_type == ni_reg_625x) { ni_writeb(0, M_Offset_Static_AI_Control(0)); ni_writeb(1, M_Offset_Static_AI_Control(0)); #if 0 @@ -742,13 +720,17 @@ static void ni_clear_ai_fifo(struct comedi_device *dev) static void win_out2(struct comedi_device *dev, uint32_t data, int reg) { + struct ni_private *devpriv = dev->private; + devpriv->stc_writew(dev, data >> 16, reg); devpriv->stc_writew(dev, data & 0xffff, reg + 1); } static uint32_t win_in2(struct comedi_device *dev, int reg) { + struct ni_private *devpriv = dev->private; uint32_t bits; + bits = devpriv->stc_readw(dev, reg) << 16; bits |= devpriv->stc_readw(dev, reg + 1); return bits; @@ -758,6 +740,7 @@ static uint32_t win_in2(struct comedi_device *dev, int reg) static inline void ni_ao_win_outw(struct comedi_device *dev, uint16_t data, int addr) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->window_lock, flags); @@ -769,6 +752,7 @@ static inline void ni_ao_win_outw(struct comedi_device *dev, uint16_t data, static inline void ni_ao_win_outl(struct comedi_device *dev, uint32_t data, int addr) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->window_lock, flags); @@ -779,6 +763,7 @@ static inline void ni_ao_win_outl(struct comedi_device *dev, uint32_t data, static inline unsigned short ni_ao_win_inw(struct comedi_device *dev, int addr) { + struct ni_private *devpriv = dev->private; unsigned long flags; unsigned short data; @@ -814,6 +799,7 @@ static inline void ni_set_bits(struct comedi_device *dev, int reg, static irqreturn_t ni_E_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct ni_private *devpriv = dev->private; unsigned short a_status; unsigned short b_status; unsigned int ai_mite_status = 0; @@ -823,7 +809,7 @@ static irqreturn_t ni_E_interrupt(int irq, void *d) struct mite_struct *mite = devpriv->mite; #endif - if (dev->attached == 0) + if (!dev->attached) return IRQ_NONE; smp_mb(); /* make sure dev->attached is checked before handler does anything else. */ @@ -872,30 +858,32 @@ static irqreturn_t ni_E_interrupt(int irq, void *d) #ifdef PCIDMA static void ni_sync_ai_dma(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct ni_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ai_mite_chan) - mite_sync_input_dma(devpriv->ai_mite_chan, s->async); + mite_sync_input_dma(devpriv->ai_mite_chan, s); spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } static void mite_handle_b_linkc(struct mite_struct *mite, struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; + struct ni_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV]; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); - if (devpriv->ao_mite_chan) { - mite_sync_output_dma(devpriv->ao_mite_chan, s->async); - } + if (devpriv->ao_mite_chan) + mite_sync_output_dma(devpriv->ao_mite_chan, s); spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } static int ni_ao_wait_for_dma_load(struct comedi_device *dev) { + struct ni_private *devpriv = dev->private; static const int timeout = 10000; int i; for (i = 0; i < timeout; i++) { @@ -918,6 +906,8 @@ static int ni_ao_wait_for_dma_load(struct comedi_device *dev) #endif /* PCIDMA */ static void ni_handle_eos(struct comedi_device *dev, struct comedi_subdevice *s) { + struct ni_private *devpriv = dev->private; + if (devpriv->aimode == AIMODE_SCAN) { #ifdef PCIDMA static const int timeout = 10; @@ -935,14 +925,13 @@ static void ni_handle_eos(struct comedi_device *dev, struct comedi_subdevice *s) #endif } /* handle special case of single scan using AI_End_On_End_Of_Scan */ - if ((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)) { + if ((devpriv->ai_cmd2 & AI_End_On_End_Of_Scan)) shutdown_ai_command(dev); - } } static void shutdown_ai_command(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; #ifdef PCIDMA ni_ai_drain_dma(dev); @@ -954,63 +943,35 @@ static void shutdown_ai_command(struct comedi_device *dev) s->async->events |= COMEDI_CB_EOA; } -static void ni_event(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW | - COMEDI_CB_EOA)) { - switch (s - dev->subdevices) { - case NI_AI_SUBDEV: - ni_ai_reset(dev, s); - break; - case NI_AO_SUBDEV: - ni_ao_reset(dev, s); - break; - case NI_GPCT0_SUBDEV: - case NI_GPCT1_SUBDEV: - ni_gpct_cancel(dev, s); - break; - case NI_DIO_SUBDEV: - ni_cdio_cancel(dev, s); - break; - default: - break; - } - } - comedi_event(dev, s); -} - static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index) { #ifdef PCIDMA - struct comedi_subdevice *s = - dev->subdevices + NI_GPCT_SUBDEV(counter_index); + struct ni_private *devpriv = dev->private; + struct comedi_subdevice *s; + + s = &dev->subdevices[NI_GPCT_SUBDEV(counter_index)]; ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index], s); - if (s->async->events) - ni_event(dev, s); + cfc_handle_events(dev, s); #endif } static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status) { + struct ni_private *devpriv = dev->private; unsigned short ack = 0; - if (a_status & AI_SC_TC_St) { + if (a_status & AI_SC_TC_St) ack |= AI_SC_TC_Interrupt_Ack; - } - if (a_status & AI_START1_St) { + if (a_status & AI_START1_St) ack |= AI_START1_Interrupt_Ack; - } - if (a_status & AI_START_St) { + if (a_status & AI_START_St) ack |= AI_START_Interrupt_Ack; - } - if (a_status & AI_STOP_St) { + if (a_status & AI_STOP_St) /* not sure why we used to ack the START here also, instead of doing it independently. Frank Hess 2007-07-06 */ - ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack */ ; - } + ack |= AI_STOP_Interrupt_Ack /*| AI_START_Interrupt_Ack */; if (ack) devpriv->stc_writew(dev, ack, Interrupt_A_Ack_Register); } @@ -1018,22 +979,16 @@ static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status) static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, unsigned ai_mite_status) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct ni_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; /* 67xx boards don't have ai subdevice, but their gpct0 might generate an a interrupt */ if (s->type == COMEDI_SUBD_UNUSED) return; -#ifdef DEBUG_INTERRUPT - printk - ("ni_mio_common: interrupt: a_status=%04x ai_mite_status=%08x\n", - status, ai_mite_status); - ni_mio_print_status_a(status); -#endif #ifdef PCIDMA - if (ai_mite_status & CHSR_LINKC) { + if (ai_mite_status & CHSR_LINKC) ni_sync_ai_dma(dev); - } if (ai_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | @@ -1041,7 +996,6 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, printk ("unknown mite interrupt, ack! (ai_mite_status=%08x)\n", ai_mite_status); - /* mite_print_chsr(ai_mite_status); */ s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; /* disable_irq(dev->irq); */ } @@ -1055,10 +1009,10 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, ("ni_mio_common: a_status=0xffff. Card removed?\n"); /* we probably aren't even running a command now, * so it's a good idea to be careful. */ - if (comedi_get_subdevice_runflags(s) & SRF_RUNNING) { + if (comedi_is_subdevice_running(s)) { s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - ni_event(dev, s); + cfc_handle_events(dev, s); } return; } @@ -1066,7 +1020,6 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, AI_SC_TC_Error_St)) { printk("ni_mio_common: ai error a_status=%04x\n", status); - ni_mio_print_status_a(status); shutdown_ai_command(dev); @@ -1074,17 +1027,12 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, if (status & (AI_Overrun_St | AI_Overflow_St)) s->async->events |= COMEDI_CB_OVERFLOW; - ni_event(dev, s); - + cfc_handle_events(dev, s); return; } if (status & AI_SC_TC_St) { -#ifdef DEBUG_INTERRUPT - printk("ni_mio_common: SC_TC interrupt\n"); -#endif - if (!devpriv->ai_continuous) { + if (!devpriv->ai_continuous) shutdown_ai_command(dev); - } } } #ifndef PCIDMA @@ -1103,46 +1051,31 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, } #endif /* !PCIDMA */ - if ((status & AI_STOP_St)) { + if ((status & AI_STOP_St)) ni_handle_eos(dev, s); - } - ni_event(dev, s); - -#ifdef DEBUG_INTERRUPT - status = devpriv->stc_readw(dev, AI_Status_1_Register); - if (status & Interrupt_A_St) { - printk - ("handle_a_interrupt: didn't clear interrupt? status=0x%x\n", - status); - } -#endif + cfc_handle_events(dev, s); } static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) { + struct ni_private *devpriv = dev->private; unsigned short ack = 0; - if (b_status & AO_BC_TC_St) { + + if (b_status & AO_BC_TC_St) ack |= AO_BC_TC_Interrupt_Ack; - } - if (b_status & AO_Overrun_St) { + if (b_status & AO_Overrun_St) ack |= AO_Error_Interrupt_Ack; - } - if (b_status & AO_START_St) { + if (b_status & AO_START_St) ack |= AO_START_Interrupt_Ack; - } - if (b_status & AO_START1_St) { + if (b_status & AO_START1_St) ack |= AO_START1_Interrupt_Ack; - } - if (b_status & AO_UC_TC_St) { + if (b_status & AO_UC_TC_St) ack |= AO_UC_TC_Interrupt_Ack; - } - if (b_status & AO_UI2_TC_St) { + if (b_status & AO_UI2_TC_St) ack |= AO_UI2_TC_Interrupt_Ack; - } - if (b_status & AO_UPDATE_St) { + if (b_status & AO_UPDATE_St) ack |= AO_UPDATE_Interrupt_Ack; - } if (ack) devpriv->stc_writew(dev, ack, Interrupt_B_Ack_Register); } @@ -1150,19 +1083,14 @@ static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) static void handle_b_interrupt(struct comedi_device *dev, unsigned short b_status, unsigned ao_mite_status) { - struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; + struct ni_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV]; /* unsigned short ack=0; */ -#ifdef DEBUG_INTERRUPT - printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n", - b_status, ao_mite_status); - ni_mio_print_status_b(b_status); -#endif #ifdef PCIDMA /* Currently, mite.c requires us to handle LINKC */ - if (ao_mite_status & CHSR_LINKC) { + if (ao_mite_status & CHSR_LINKC) mite_handle_b_linkc(devpriv->mite, dev); - } if (ao_mite_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_MRDY | CHSR_DRDY | CHSR_DRQ1 | CHSR_DRQ0 | CHSR_ERROR | @@ -1170,7 +1098,6 @@ static void handle_b_interrupt(struct comedi_device *dev, printk ("unknown mite interrupt, ack! (ao_mite_status=%08x)\n", ao_mite_status); - /* mite_print_chsr(ao_mite_status); */ s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } #endif @@ -1184,12 +1111,9 @@ static void handle_b_interrupt(struct comedi_device *dev, s->async->events |= COMEDI_CB_OVERFLOW; } - if (b_status & AO_BC_TC_St) { - MDPRINTK - ("ni_mio_common: AO BC_TC status=0x%04x status2=0x%04x\n", - b_status, devpriv->stc_readw(dev, AO_Status_2_Register)); + if (b_status & AO_BC_TC_St) s->async->events |= COMEDI_CB_EOA; - } + #ifndef PCIDMA if (b_status & AO_FIFO_Request_St) { int ret; @@ -1205,80 +1129,37 @@ static void handle_b_interrupt(struct comedi_device *dev, } #endif - ni_event(dev, s); -} - -#ifdef DEBUG_STATUS_A -static const char *const status_a_strings[] = { - "passthru0", "fifo", "G0_gate", "G0_TC", - "stop", "start", "sc_tc", "start1", - "start2", "sc_tc_error", "overflow", "overrun", - "fifo_empty", "fifo_half_full", "fifo_full", "interrupt_a" -}; - -static void ni_mio_print_status_a(int status) -{ - int i; - - printk("A status:"); - for (i = 15; i >= 0; i--) { - if (status & (1 << i)) { - printk(" %s", status_a_strings[i]); - } - } - printk("\n"); + cfc_handle_events(dev, s); } -#endif - -#ifdef DEBUG_STATUS_B -static const char *const status_b_strings[] = { - "passthru1", "fifo", "G1_gate", "G1_TC", - "UI2_TC", "UPDATE", "UC_TC", "BC_TC", - "start1", "overrun", "start", "bc_tc_error", - "fifo_empty", "fifo_half_full", "fifo_full", "interrupt_b" -}; - -static void ni_mio_print_status_b(int status) -{ - int i; - - printk("B status:"); - for (i = 15; i >= 0; i--) { - if (status & (1 << i)) { - printk(" %s", status_b_strings[i]); - } - } - printk("\n"); -} -#endif #ifndef PCIDMA static void ni_ao_fifo_load(struct comedi_device *dev, struct comedi_subdevice *s, int n) { + const struct ni_board_struct *board = comedi_board(dev); struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; int chan; int i; - short d; + unsigned short d; u32 packed_data; int range; int err = 1; chan = async->cur_chan; for (i = 0; i < n; i++) { - err &= comedi_buf_get(async, &d); + err &= comedi_buf_get(s, &d); if (err == 0) break; range = CR_RANGE(cmd->chanlist[chan]); - if (boardtype.reg_type & ni_reg_6xxx_mask) { + if (board->reg_type & ni_reg_6xxx_mask) { packed_data = d & 0xffff; /* 6711 only has 16 bit wide ao fifo */ - if (boardtype.reg_type != ni_reg_6711) { - err &= comedi_buf_get(async, &d); + if (board->reg_type != ni_reg_6711) { + err &= comedi_buf_get(s, &d); if (err == 0) break; chan++; @@ -1293,9 +1174,8 @@ static void ni_ao_fifo_load(struct comedi_device *dev, chan %= cmd->chanlist_len; } async->cur_chan = chan; - if (err == 0) { + if (err == 0) async->events |= COMEDI_CB_OVERFLOW; - } } /* @@ -1317,17 +1197,18 @@ 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); int n; - n = comedi_buf_read_n_available(s->async); + n = comedi_buf_read_n_available(s); if (n == 0) { s->async->events |= COMEDI_CB_OVERFLOW; return 0; } n /= sizeof(short); - if (n > boardtype.ao_fifo_depth / 2) - n = boardtype.ao_fifo_depth / 2; + if (n > board->ao_fifo_depth / 2) + n = board->ao_fifo_depth / 2; ni_ao_fifo_load(dev, s, n); @@ -1339,21 +1220,23 @@ 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); + struct ni_private *devpriv = dev->private; int n; /* reset fifo */ devpriv->stc_writew(dev, 1, DAC_FIFO_Clear); - if (boardtype.reg_type & ni_reg_6xxx_mask) + if (board->reg_type & ni_reg_6xxx_mask) ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x); /* load some data */ - n = comedi_buf_read_n_available(s->async); + n = comedi_buf_read_n_available(s); if (n == 0) return 0; n /= sizeof(short); - if (n > boardtype.ao_fifo_depth) - n = boardtype.ao_fifo_depth; + if (n > board->ao_fifo_depth) + n = board->ao_fifo_depth; ni_ao_fifo_load(dev, s, n); @@ -1363,11 +1246,13 @@ static int ni_ao_prep_fifo(struct comedi_device *dev, static void ni_ai_fifo_read(struct comedi_device *dev, struct comedi_subdevice *s, int n) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; struct comedi_async *async = s->async; int i; - if (boardtype.reg_type == ni_reg_611x) { - short data[2]; + if (board->reg_type == ni_reg_611x) { + unsigned short data[2]; u32 dl; for (i = 0; i < n / 2; i++) { @@ -1383,8 +1268,8 @@ static void ni_ai_fifo_read(struct comedi_device *dev, data[0] = dl & 0xffff; cfc_write_to_buffer(s, data[0]); } - } else if (boardtype.reg_type == ni_reg_6143) { - short data[2]; + } else if (board->reg_type == ni_reg_6143) { + unsigned short data[2]; u32 dl; /* This just reads the FIFO assuming the data is present, no checks on the FIFO status are performed */ @@ -1421,10 +1306,11 @@ 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); + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; int n; - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; - n = boardtype.ai_fifo_depth / 2; + n = board->ai_fifo_depth / 2; ni_ai_fifo_read(dev, s, n); } @@ -1433,6 +1319,7 @@ static void ni_handle_fifo_half_full(struct comedi_device *dev) #ifdef PCIDMA static int ni_ai_drain_dma(struct comedi_device *dev) { + struct ni_private *devpriv = dev->private; int i; static const int timeout = 10000; unsigned long flags; @@ -1470,13 +1357,15 @@ static int ni_ai_drain_dma(struct comedi_device *dev) */ static void ni_handle_fifo_dregs(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; - short data[2]; + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; + unsigned short data[2]; u32 dl; - short fifo_empty; + unsigned short fifo_empty; int i; - if (boardtype.reg_type == ni_reg_611x) { + if (board->reg_type == ni_reg_611x) { while ((devpriv->stc_readw(dev, AI_Status_1_Register) & AI_FIFO_Empty_St) == 0) { @@ -1487,7 +1376,7 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) data[1] = (dl & 0xffff); cfc_write_array_to_buffer(s, data, sizeof(data)); } - } else if (boardtype.reg_type == ni_reg_6143) { + } else if (board->reg_type == ni_reg_6143) { i = 0; while (ni_readl(AIFIFO_Status_6143) & 0x04) { dl = ni_readl(AIFIFO_Data_6143); @@ -1534,11 +1423,13 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) static void get_last_sample_611x(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; - short data; + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv __maybe_unused = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; + unsigned short data; u32 dl; - if (boardtype.reg_type != ni_reg_611x) + if (board->reg_type != ni_reg_611x) return; /* Check if there's a single sample stuck in the FIFO */ @@ -1551,11 +1442,13 @@ static void get_last_sample_611x(struct comedi_device *dev) static void get_last_sample_6143(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; - short data; + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv __maybe_unused = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; + unsigned short data; u32 dl; - if (boardtype.reg_type != ni_reg_6143) + if (board->reg_type != ni_reg_6143) return; /* Check if there's a single sample stuck in the FIFO */ @@ -1573,11 +1466,14 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index) { + struct ni_private *devpriv = dev->private; struct comedi_async *async = s->async; - unsigned int i; + struct comedi_cmd *cmd = &async->cmd; unsigned int length = num_bytes / bytes_per_sample(s); - short *array = data; + unsigned short *array = data; unsigned int *larray = data; + unsigned int i; + for (i = 0; i < length; i++) { #ifdef PCIDMA if (s->subdev_flags & SDF_LSAMPL) @@ -1590,7 +1486,7 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, else array[i] += devpriv->ai_offset[chan_index]; chan_index++; - chan_index %= async->cmd.chanlist_len; + chan_index %= cmd->chanlist_len; } } @@ -1598,7 +1494,9 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, static int ni_ai_setup_MITE_dma(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; int retval; unsigned long flags; @@ -1608,7 +1506,7 @@ static int ni_ai_setup_MITE_dma(struct comedi_device *dev) /* printk("comedi_debug: using mite channel %i for ai.\n", devpriv->ai_mite_chan->channel); */ /* write alloc the entire buffer */ - comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz); + comedi_buf_write_alloc(s, s->async->prealloc_bufsz); spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ai_mite_chan == NULL) { @@ -1616,7 +1514,7 @@ static int ni_ai_setup_MITE_dma(struct comedi_device *dev) return -EIO; } - switch (boardtype.reg_type) { + switch (board->reg_type) { case ni_reg_611x: case ni_reg_6143: mite_prep_dma(devpriv->ai_mite_chan, 32, 16); @@ -1637,7 +1535,9 @@ static int ni_ai_setup_MITE_dma(struct comedi_device *dev) static int ni_ao_setup_MITE_dma(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV]; int retval; unsigned long flags; @@ -1646,11 +1546,11 @@ static int ni_ao_setup_MITE_dma(struct comedi_device *dev) return retval; /* read alloc the entire buffer */ - comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz); + comedi_buf_read_alloc(s, s->async->prealloc_bufsz); spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->ao_mite_chan) { - if (boardtype.reg_type & (ni_reg_611x | ni_reg_6713)) { + if (board->reg_type & (ni_reg_611x | ni_reg_6713)) { mite_prep_dma(devpriv->ao_mite_chan, 32, 32); } else { /* doing 32 instead of 16 bit wide transfers from memory @@ -1675,6 +1575,9 @@ static int ni_ao_setup_MITE_dma(struct comedi_device *dev) static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + ni_release_ai_mite_channel(dev); /* ai configuration */ devpriv->stc_writew(dev, AI_Configuration_Start | AI_Reset, @@ -1688,7 +1591,7 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s) ni_clear_ai_fifo(dev); - if (boardtype.reg_type != ni_reg_6143) + if (board->reg_type != ni_reg_6143) ni_writeb(0, Misc_Command); devpriv->stc_writew(dev, AI_Disarm, AI_Command_1_Register); /* reset pulses */ @@ -1699,7 +1602,7 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->stc_writew(dev, 0x0000, AI_Mode_2_Register); /* generate FIFO interrupts on non-empty */ devpriv->stc_writew(dev, (0 << 6) | 0x0000, AI_Mode_3_Register); - if (boardtype.reg_type == ni_reg_611x) { + if (board->reg_type == ni_reg_611x) { devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width | AI_SOC_Polarity | AI_LOCALMUX_CLK_Pulse_Width, @@ -1712,7 +1615,7 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s) AI_CONVERT_Output_Select (AI_CONVERT_Output_Enable_High), AI_Output_Control_Register); - } else if (boardtype.reg_type == ni_reg_6143) { + } else if (board->reg_type == ni_reg_6143) { devpriv->stc_writew(dev, AI_SHIFTIN_Pulse_Width | AI_SOC_Polarity | AI_LOCALMUX_CLK_Pulse_Width, @@ -1737,7 +1640,7 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s) AI_EXTMUX_CLK_Output_Select(0) | AI_LOCALMUX_CLK_Output_Select(2) | AI_SC_TC_Output_Select(3); - if (boardtype.reg_type == ni_reg_622x) + if (board->reg_type == ni_reg_622x) ai_output_control_bits |= AI_CONVERT_Output_Select (AI_CONVERT_Output_Enable_High); @@ -1765,20 +1668,18 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s) static int ni_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned long flags = 0; + unsigned long flags; int count; /* lock to avoid race with interrupt handler */ - if (in_interrupt() == 0) - spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); #ifndef PCIDMA ni_handle_fifo_dregs(dev); #else ni_sync_ai_dma(dev); #endif count = s->async->buf_write_count - s->async->buf_read_count; - if (in_interrupt() == 0) - spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return count; } @@ -1787,8 +1688,10 @@ static int ni_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; int i, n; - const unsigned int mask = (1 << boardtype.adbits) - 1; + const unsigned int mask = (1 << board->adbits) - 1; unsigned signbits; unsigned short d; unsigned long dl; @@ -1798,7 +1701,7 @@ static int ni_ai_insn_read(struct comedi_device *dev, ni_clear_ai_fifo(dev); signbits = devpriv->ai_offset[0]; - if (boardtype.reg_type == ni_reg_611x) { + if (board->reg_type == ni_reg_611x) { for (n = 0; n < num_adc_stages_611x; n++) { devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register); @@ -1831,7 +1734,7 @@ static int ni_ai_insn_read(struct comedi_device *dev, d += signbits; data[n] = d; } - } else if (boardtype.reg_type == ni_reg_6143) { + } else if (board->reg_type == ni_reg_6143) { for (n = 0; n < insn->n; n++) { devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register); @@ -1867,7 +1770,7 @@ static int ni_ai_insn_read(struct comedi_device *dev, ("ni_mio_common: timeout in ni_ai_insn_read\n"); return -ETIME; } - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { data[n] = ni_readl(M_Offset_AI_FIFO_Data) & mask; } else { @@ -1880,9 +1783,11 @@ static int ni_ai_insn_read(struct comedi_device *dev, return insn->n; } -void ni_prime_channelgain_list(struct comedi_device *dev) +static void ni_prime_channelgain_list(struct comedi_device *dev) { + struct ni_private *devpriv = dev->private; int i; + devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register); for (i = 0; i < NI_TIMEOUT; ++i) { if (!(devpriv->stc_readw(dev, @@ -1900,6 +1805,8 @@ 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); + struct ni_private *devpriv = dev->private; unsigned int chan, range, aref; unsigned int i; unsigned offset; @@ -1908,12 +1815,12 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev, devpriv->stc_writew(dev, 1, Configuration_Memory_Clear); -/* offset = 1 << (boardtype.adbits - 1); */ +/* offset = 1 << (board->adbits - 1); */ if ((list[0] & CR_ALT_SOURCE)) { unsigned bypass_bits; chan = CR_CHAN(list[0]); range = CR_RANGE(list[0]); - range_code = ni_gainlkup[boardtype.gainlkup][range]; + range_code = ni_gainlkup[board->gainlkup][range]; dither = ((list[0] & CR_ALT_FILTER) != 0); bypass_bits = MSeries_AI_Bypass_Config_FIFO_Bit; bypass_bits |= chan; @@ -1940,7 +1847,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev, range = CR_RANGE(list[i]); dither = ((list[i] & CR_ALT_FILTER) != 0); - range_code = ni_gainlkup[boardtype.gainlkup][range]; + range_code = ni_gainlkup[board->gainlkup][range]; devpriv->ai_offset[i] = offset; switch (aref) { case AREF_DIFF: @@ -1960,7 +1867,7 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev, } config_bits |= MSeries_AI_Config_Channel_Bits(chan); config_bits |= - MSeries_AI_Config_Bank_Bits(boardtype.reg_type, chan); + MSeries_AI_Config_Bank_Bits(board->reg_type, chan); config_bits |= MSeries_AI_Config_Gain_Bits(range_code); if (i == n_chan - 1) config_bits |= MSeries_AI_Config_Last_Channel_Bit; @@ -2005,18 +1912,20 @@ static void ni_m_series_load_channelgain_list(struct comedi_device *dev, static void ni_load_channelgain_list(struct comedi_device *dev, unsigned int n_chan, unsigned int *list) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; unsigned int chan, range, aref; unsigned int i; unsigned int hi, lo; unsigned offset; unsigned int dither; - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { ni_m_series_load_channelgain_list(dev, n_chan, list); return; } - if (n_chan == 1 && (boardtype.reg_type != ni_reg_611x) - && (boardtype.reg_type != ni_reg_6143)) { + if (n_chan == 1 && (board->reg_type != ni_reg_611x) + && (board->reg_type != ni_reg_6143)) { if (devpriv->changain_state && devpriv->changain_spec == list[0]) { /* ready to go. */ @@ -2031,7 +1940,7 @@ static void ni_load_channelgain_list(struct comedi_device *dev, devpriv->stc_writew(dev, 1, Configuration_Memory_Clear); /* Set up Calibration mode if required */ - if (boardtype.reg_type == ni_reg_6143) { + if (board->reg_type == ni_reg_6143) { if ((list[0] & CR_ALT_SOURCE) && !devpriv->ai_calib_source_enabled) { /* Strobe Relay enable bit */ @@ -2055,9 +1964,9 @@ static void ni_load_channelgain_list(struct comedi_device *dev, } } - offset = 1 << (boardtype.adbits - 1); + offset = 1 << (board->adbits - 1); for (i = 0; i < n_chan; i++) { - if ((boardtype.reg_type != ni_reg_6143) + if ((board->reg_type != ni_reg_6143) && (list[i] & CR_ALT_SOURCE)) { chan = devpriv->ai_calib_source; } else { @@ -2068,21 +1977,21 @@ static void ni_load_channelgain_list(struct comedi_device *dev, dither = ((list[i] & CR_ALT_FILTER) != 0); /* fix the external/internal range differences */ - range = ni_gainlkup[boardtype.gainlkup][range]; - if (boardtype.reg_type == ni_reg_611x) + range = ni_gainlkup[board->gainlkup][range]; + if (board->reg_type == ni_reg_611x) devpriv->ai_offset[i] = offset; else devpriv->ai_offset[i] = (range & 0x100) ? 0 : offset; hi = 0; if ((list[i] & CR_ALT_SOURCE)) { - if (boardtype.reg_type == ni_reg_611x) + if (board->reg_type == ni_reg_611x) ni_writew(CR_CHAN(list[i]) & 0x0003, Calibration_Channel_Select_611x); } else { - if (boardtype.reg_type == ni_reg_611x) + if (board->reg_type == ni_reg_611x) aref = AREF_DIFF; - else if (boardtype.reg_type == ni_reg_6143) + else if (board->reg_type == ni_reg_6143) aref = AREF_OTHER; switch (aref) { case AREF_DIFF: @@ -2102,7 +2011,7 @@ static void ni_load_channelgain_list(struct comedi_device *dev, ni_writew(hi, Configuration_Memory_High); - if (boardtype.reg_type != ni_reg_6143) { + if (board->reg_type != ni_reg_6143) { lo = range; if (i == n_chan - 1) lo |= AI_LAST_CHANNEL; @@ -2114,8 +2023,8 @@ static void ni_load_channelgain_list(struct comedi_device *dev, } /* prime the channel/gain list */ - if ((boardtype.reg_type != ni_reg_611x) - && (boardtype.reg_type != ni_reg_6143)) { + if ((board->reg_type != ni_reg_611x) + && (board->reg_type != ni_reg_6143)) { ni_prime_channelgain_list(dev); } } @@ -2123,7 +2032,9 @@ static void ni_load_channelgain_list(struct comedi_device *dev, static int ni_ns_to_timer(const struct comedi_device *dev, unsigned nanosec, int round_mode) { + struct ni_private *devpriv = dev->private; int divider; + switch (round_mode) { case TRIG_ROUND_NEAREST: default: @@ -2141,122 +2052,94 @@ static int ni_ns_to_timer(const struct comedi_device *dev, unsigned nanosec, static unsigned ni_timer_to_ns(const struct comedi_device *dev, int timer) { + struct ni_private *devpriv = dev->private; + return devpriv->clock_ns * (timer + 1); } static unsigned ni_min_ai_scan_period_ns(struct comedi_device *dev, unsigned num_channels) { - switch (boardtype.reg_type) { + const struct ni_board_struct *board = comedi_board(dev); + + switch (board->reg_type) { case ni_reg_611x: case ni_reg_6143: /* simultaneously-sampled inputs */ - return boardtype.ai_speed; + return board->ai_speed; break; default: /* multiplexed inputs */ break; } - return boardtype.ai_speed * num_channels; + return board->ai_speed * num_channels; } 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); + struct ni_private *devpriv = dev->private; int err = 0; - int tmp; - int sources; + unsigned int tmp; + unsigned int sources; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - if ((cmd->flags & CMDF_WRITE)) { + if ((cmd->flags & CMDF_WRITE)) cmd->flags &= ~CMDF_WRITE; - } - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); - tmp = cmd->convert_src; sources = TRIG_TIMER | TRIG_EXT; - if ((boardtype.reg_type == ni_reg_611x) - || (boardtype.reg_type == ni_reg_6143)) + if (board->reg_type == ni_reg_611x || + board->reg_type == ni_reg_6143) sources |= TRIG_NOW; - cmd->convert_src &= sources; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, sources); - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->start_src != TRIG_NOW && - cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_OTHER) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + 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 (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_EXT) { - /* external trigger */ - unsigned int tmp = CR_CHAN(cmd->start_arg); + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + tmp = CR_CHAN(cmd->start_arg); if (tmp > 16) tmp = 16; tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE)); - if (cmd->start_arg != tmp) { - cmd->start_arg = tmp; - err++; - } - } else { - if (cmd->start_arg != 0) { - /* true for both TRIG_NOW and TRIG_INT */ - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, tmp); + break; } + if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < ni_min_ai_scan_period_ns(dev, - cmd-> - chanlist_len)) - { - cmd->scan_begin_arg = - ni_min_ai_scan_period_ns(dev, cmd->chanlist_len); - err++; - } - if (cmd->scan_begin_arg > devpriv->clock_ns * 0xffffff) { - cmd->scan_begin_arg = devpriv->clock_ns * 0xffffff; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + ni_min_ai_scan_period_ns(dev, cmd->chanlist_len)); + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, + devpriv->clock_ns * 0xffffff); } else if (cmd->scan_begin_src == TRIG_EXT) { /* external trigger */ unsigned int tmp = CR_CHAN(cmd->scan_begin_arg); @@ -2264,32 +2147,20 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (tmp > 16) tmp = 16; tmp |= (cmd->scan_begin_arg & (CR_INVERT | CR_EDGE)); - if (cmd->scan_begin_arg != tmp) { - cmd->scan_begin_arg = tmp; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, tmp); } else { /* TRIG_OTHER */ - if (cmd->scan_begin_arg) { - cmd->scan_begin_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); } + if (cmd->convert_src == TRIG_TIMER) { - if ((boardtype.reg_type == ni_reg_611x) - || (boardtype.reg_type == ni_reg_6143)) { - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } + if ((board->reg_type == ni_reg_611x) + || (board->reg_type == ni_reg_6143)) { + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); } else { - if (cmd->convert_arg < boardtype.ai_speed) { - cmd->convert_arg = boardtype.ai_speed; - err++; - } - if (cmd->convert_arg > devpriv->clock_ns * 0xffff) { - cmd->convert_arg = devpriv->clock_ns * 0xffff; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + board->ai_speed); + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, + devpriv->clock_ns * 0xffff); } } else if (cmd->convert_src == TRIG_EXT) { /* external trigger */ @@ -2298,40 +2169,23 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (tmp > 16) tmp = 16; tmp |= (cmd->convert_arg & (CR_ALT_FILTER | CR_INVERT)); - if (cmd->convert_arg != tmp) { - cmd->convert_arg = tmp; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, tmp); } else if (cmd->convert_src == TRIG_NOW) { - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); + if (cmd->stop_src == TRIG_COUNT) { unsigned int max_count = 0x01000000; - if (boardtype.reg_type == ni_reg_611x) + if (board->reg_type == ni_reg_611x) max_count -= num_adc_stages_611x; - if (cmd->stop_arg > max_count) { - cmd->stop_arg = max_count; - err++; - } - if (cmd->stop_arg < 1) { - cmd->stop_arg = 1; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->stop_arg, max_count); + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -2351,8 +2205,8 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, err++; } if (cmd->convert_src == TRIG_TIMER) { - if ((boardtype.reg_type != ni_reg_611x) - && (boardtype.reg_type != ni_reg_6143)) { + if ((board->reg_type != ni_reg_611x) + && (board->reg_type != ni_reg_6143)) { tmp = cmd->convert_arg; cmd->convert_arg = ni_timer_to_ns(dev, ni_ns_to_timer(dev, @@ -2380,6 +2234,8 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; const struct comedi_cmd *cmd = &s->async->cmd; int timer; int mode1 = 0; /* mode1 is needed for both stop and convert */ @@ -2388,7 +2244,6 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) unsigned int stop_count; int interrupt_a_enable = 0; - MDPRINTK("ni_ai_cmd\n"); if (dev->irq == 0) { comedi_error(dev, "cannot run command without an irq"); return -EIO; @@ -2435,8 +2290,8 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) mode2 &= ~AI_SC_Reload_Mode; devpriv->stc_writew(dev, mode2, AI_Mode_2_Register); - if (cmd->chanlist_len == 1 || (boardtype.reg_type == ni_reg_611x) - || (boardtype.reg_type == ni_reg_6143)) { + if (cmd->chanlist_len == 1 || (board->reg_type == ni_reg_611x) + || (board->reg_type == ni_reg_6143)) { start_stop_select |= AI_STOP_Polarity; start_stop_select |= AI_STOP_Select(31); /* logic low */ start_stop_select |= AI_STOP_Sync; @@ -2451,7 +2306,7 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_COUNT: stop_count = cmd->stop_arg - 1; - if (boardtype.reg_type == ni_reg_611x) { + if (board->reg_type == ni_reg_611x) { /* have to take 3 stage adc pipeline into account */ stop_count += num_adc_stages_611x; } @@ -2626,15 +2481,11 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) ni_set_bits(dev, Interrupt_A_Enable_Register, interrupt_a_enable, 1); - - MDPRINTK("Interrupt_A_Enable_Register = 0x%04x\n", - devpriv->int_a_enable_reg); } else { /* interrupt on nothing */ ni_set_bits(dev, Interrupt_A_Enable_Register, ~0, 0); /* XXX start polling if necessary */ - MDPRINTK("interrupting on nothing\n"); } /* end configuration */ @@ -2660,33 +2511,30 @@ static int ni_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (retval) return retval; } - /* mite_dump_regs(devpriv->mite); */ #endif - switch (cmd->start_src) { - case TRIG_NOW: + if (cmd->start_src == TRIG_NOW) { /* AI_START1_Pulse */ devpriv->stc_writew(dev, AI_START1_Pulse | devpriv->ai_cmd2, AI_Command_2_Register); s->async->inttrig = NULL; - break; - case TRIG_EXT: + } else if (cmd->start_src == TRIG_EXT) { s->async->inttrig = NULL; - break; - case TRIG_INT: - s->async->inttrig = &ni_ai_inttrig; - break; + } else { /* TRIG_INT */ + s->async->inttrig = ni_ai_inttrig; } - MDPRINTK("exit ni_ai_cmd\n"); - return 0; } -static int ni_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_ai_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != 0) + struct ni_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; devpriv->stc_writew(dev, AI_START1_Pulse | devpriv->ai_cmd2, @@ -2705,6 +2553,9 @@ static int ni_ai_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); + struct ni_private *devpriv = dev->private; + if (insn->n < 1) return -EINVAL; @@ -2712,7 +2563,7 @@ static int ni_ai_insn_config(struct comedi_device *dev, case INSN_CONFIG_ANALOG_TRIG: return ni_ai_config_analog_trig(dev, s, insn, data); case INSN_CONFIG_ALT_SOURCE: - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { if (data[1] & ~(MSeries_AI_Bypass_Cal_Sel_Pos_Mask | MSeries_AI_Bypass_Cal_Sel_Neg_Mask | MSeries_AI_Bypass_Mode_Mux_Mask | @@ -2720,7 +2571,7 @@ static int ni_ai_insn_config(struct comedi_device *dev, return -EINVAL; } devpriv->ai_calib_source = data[1]; - } else if (boardtype.reg_type == ni_reg_6143) { + } else if (board->reg_type == ni_reg_6143) { unsigned int calib_source; calib_source = data[1] & 0xf; @@ -2740,7 +2591,7 @@ static int ni_ai_insn_config(struct comedi_device *dev, if (calib_source >= 8) return -EINVAL; devpriv->ai_calib_source = calib_source; - if (boardtype.reg_type == ni_reg_611x) { + if (board->reg_type == ni_reg_611x) { ni_writeb(calib_source_adjust, Cal_Gain_Select_611x); } @@ -2758,6 +2609,8 @@ static int ni_ai_config_analog_trig(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; unsigned int a, b, modebits; int err = 0; @@ -2765,14 +2618,14 @@ static int ni_ai_config_analog_trig(struct comedi_device *dev, * data[2] is analog line * data[3] is set level * data[4] is reset level */ - if (!boardtype.has_analog_trig) + if (!board->has_analog_trig) return -EINVAL; if ((data[1] & 0xffff0000) != COMEDI_EV_SCAN_BEGIN) { data[1] &= (COMEDI_EV_SCAN_BEGIN | 0xffff); err++; } - if (data[2] >= boardtype.n_adchan) { - data[2] = boardtype.n_adchan - 1; + if (data[2] >= board->n_adchan) { + data[2] = board->n_adchan - 1; err++; } if (data[3] > 255) { /* a */ @@ -2856,23 +2709,24 @@ static void ni_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index) { + const struct ni_board_struct *board = comedi_board(dev); struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + unsigned int length = num_bytes / sizeof(short); + unsigned int offset = 1 << (board->aobits - 1); + unsigned short *array = data; unsigned int range; unsigned int i; - unsigned int offset; - unsigned int length = num_bytes / sizeof(short); - short *array = data; - offset = 1 << (boardtype.aobits - 1); for (i = 0; i < length; i++) { - range = CR_RANGE(async->cmd.chanlist[chan_index]); - if (boardtype.ao_unipolar == 0 || (range & 1) == 0) + range = CR_RANGE(cmd->chanlist[chan_index]); + if (board->ao_unipolar == 0 || (range & 1) == 0) array[i] -= offset; #ifdef PCIDMA array[i] = cpu_to_le16(array[i]); #endif chan_index++; - chan_index %= async->cmd.chanlist_len; + chan_index %= cmd->chanlist_len; } } @@ -2881,6 +2735,8 @@ static int ni_m_series_ao_config_chanlist(struct comedi_device *dev, unsigned int chanspec[], unsigned int n_chans, int timed) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; unsigned int range; unsigned int chan; unsigned int conf; @@ -2888,7 +2744,7 @@ static int ni_m_series_ao_config_chanlist(struct comedi_device *dev, int invert = 0; if (timed) { - for (i = 0; i < boardtype.n_aochan; ++i) { + for (i = 0; i < board->n_aochan; ++i) { devpriv->ao_conf[i] &= ~MSeries_AO_Update_Timed_Bit; ni_writeb(devpriv->ao_conf[i], M_Offset_AO_Config_Bank(i)); @@ -2952,6 +2808,8 @@ static int ni_old_ao_config_chanlist(struct comedi_device *dev, unsigned int chanspec[], unsigned int n_chans) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; unsigned int range; unsigned int chan; unsigned int conf; @@ -2963,10 +2821,10 @@ static int ni_old_ao_config_chanlist(struct comedi_device *dev, range = CR_RANGE(chanspec[i]); conf = AO_Channel(chan); - if (boardtype.ao_unipolar) { + if (board->ao_unipolar) { if ((range & 1) == 0) { conf |= AO_Bipolar; - invert = (1 << (boardtype.aobits - 1)); + invert = (1 << (board->aobits - 1)); } else { invert = 0; } @@ -2974,7 +2832,7 @@ static int ni_old_ao_config_chanlist(struct comedi_device *dev, conf |= AO_Ext_Ref; } else { conf |= AO_Bipolar; - invert = (1 << (boardtype.aobits - 1)); + invert = (1 << (board->aobits - 1)); } /* not all boards can deglitch, but this shouldn't hurt */ @@ -2997,7 +2855,9 @@ static int ni_ao_config_chanlist(struct comedi_device *dev, unsigned int chanspec[], unsigned int n_chans, int timed) { - if (boardtype.reg_type & ni_reg_m_series_mask) + const struct ni_board_struct *board = comedi_board(dev); + + if (board->reg_type & ni_reg_m_series_mask) return ni_m_series_ao_config_chanlist(dev, s, chanspec, n_chans, timed); else @@ -3008,6 +2868,8 @@ 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; + data[0] = devpriv->ao[CR_CHAN(insn->chanspec)]; return 1; @@ -3017,6 +2879,8 @@ static int ni_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int invert; @@ -3024,7 +2888,7 @@ static int ni_ao_insn_write(struct comedi_device *dev, devpriv->ao[chan] = data[0]; - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { ni_writew(data[0], M_Offset_DAC_Direct_Data(chan)); } else ni_writew(data[0] ^ invert, @@ -3037,11 +2901,13 @@ static int ni_ao_insn_write_671x(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); unsigned int invert; ao_win_out(1 << chan, AO_Immediate_671x); - invert = 1 << (boardtype.aobits - 1); + invert = 1 << (board->aobits - 1); ni_ao_config_chanlist(dev, s, &insn->chanspec, 1, 0); @@ -3055,11 +2921,14 @@ 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); + struct ni_private *devpriv = dev->private; + switch (data[0]) { case INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE: switch (data[1]) { case COMEDI_OUTPUT: - data[2] = 1 + boardtype.ao_fifo_depth * sizeof(short); + data[2] = 1 + board->ao_fifo_depth * sizeof(short); if (devpriv->mite) data[2] += devpriv->mite->fifo_size; break; @@ -3078,15 +2947,19 @@ static int ni_ao_insn_config(struct comedi_device *dev, return -EINVAL; } -static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_ao_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { + const struct ni_board_struct *board __maybe_unused = comedi_board(dev); + struct ni_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; int interrupt_b_bits; int i; static const int timeout = 1000; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; /* Null trig at beginning prevent ao start trigger from executing more than @@ -3099,7 +2972,7 @@ static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, interrupt_b_bits = AO_Error_Interrupt_Enable; #ifdef PCIDMA devpriv->stc_writew(dev, 1, DAC_FIFO_Clear); - if (boardtype.reg_type & ni_reg_6xxx_mask) + if (board->reg_type & ni_reg_6xxx_mask) ni_ao_win_outl(dev, 0x6, AO_FIFO_Offset_Load_611x); ret = ni_ao_setup_MITE_dma(dev); if (ret) @@ -3150,6 +3023,8 @@ static int ni_ao_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; const struct comedi_cmd *cmd = &s->async->cmd; int bits; int i; @@ -3164,7 +3039,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->stc_writew(dev, AO_Disarm, AO_Command_1_Register); - if (boardtype.reg_type & ni_reg_6xxx_mask) { + if (board->reg_type & ni_reg_6xxx_mask) { ao_win_out(CLEAR_WG, AO_Misc_611x); bits = 0; @@ -3217,17 +3092,16 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->stc_writew(dev, devpriv->ao_mode1, AO_Mode_1_Register); devpriv->ao_mode2 &= ~AO_BC_Initial_Load_Source; devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register); - if (cmd->stop_src == TRIG_NONE) { + if (cmd->stop_src == TRIG_NONE) devpriv->stc_writel(dev, 0xffffff, AO_BC_Load_A_Register); - } else { + else devpriv->stc_writel(dev, 0, AO_BC_Load_A_Register); - } devpriv->stc_writew(dev, AO_BC_Load, AO_Command_1_Register); devpriv->ao_mode2 &= ~AO_UC_Initial_Load_Source; devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register); switch (cmd->stop_src) { case TRIG_COUNT: - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { /* this is how the NI example code does it for m-series boards, verified correct with 6259 */ devpriv->stc_writel(dev, cmd->stop_arg - 1, AO_UC_Load_A_Register); @@ -3295,8 +3169,8 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) unsigned bits; devpriv->ao_mode1 &= ~AO_Multiple_Channels; bits = AO_UPDATE_Output_Select(AO_Update_Output_High_Z); - if (boardtype. - reg_type & (ni_reg_m_series_mask | ni_reg_6xxx_mask)) { + if (board->reg_type & + (ni_reg_m_series_mask | ni_reg_6xxx_mask)) { bits |= AO_Number_Of_Channels(0); } else { bits |= @@ -3323,14 +3197,14 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) bits = AO_BC_Source_Select | AO_UPDATE_Pulse_Width | AO_TMRDACWR_Pulse_Width; - if (boardtype.ao_fifo_depth) + if (board->ao_fifo_depth) bits |= AO_FIFO_Enable; else bits |= AO_DMA_PIO_Control; #if 0 /* F Hess: windows driver does not set AO_Number_Of_DAC_Packages bit for 6281, verified with bus analyzer. */ - if (boardtype.reg_type & ni_reg_m_series_mask) + if (board->reg_type & ni_reg_m_series_mask) bits |= AO_Number_Of_DAC_Packages; #endif devpriv->stc_writew(dev, bits, AO_Personal_Register); @@ -3346,7 +3220,7 @@ static int ni_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) AO_BC_TC_Interrupt_Enable, 1); } - s->async->inttrig = &ni_ao_inttrig; + s->async->inttrig = ni_ao_inttrig; return 0; } @@ -3354,102 +3228,68 @@ 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); + struct ni_private *devpriv = dev->private; int err = 0; - int tmp; + unsigned int tmp; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - if ((cmd->flags & CMDF_WRITE) == 0) { + if ((cmd->flags & CMDF_WRITE) == 0) cmd->flags |= CMDF_WRITE; - } - - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + 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->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_EXT) { - /* external trigger */ - unsigned int tmp = CR_CHAN(cmd->start_arg); + switch (cmd->start_src) { + case TRIG_INT: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + tmp = CR_CHAN(cmd->start_arg); if (tmp > 18) tmp = 18; tmp |= (cmd->start_arg & (CR_INVERT | CR_EDGE)); - if (cmd->start_arg != tmp) { - cmd->start_arg = tmp; - err++; - } - } else { - if (cmd->start_arg != 0) { - /* true for both TRIG_NOW and TRIG_INT */ - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, tmp); + break; } + if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < boardtype.ao_speed) { - cmd->scan_begin_arg = boardtype.ao_speed; - err++; - } - if (cmd->scan_begin_arg > devpriv->clock_ns * 0xffffff) { /* XXX check */ - cmd->scan_begin_arg = devpriv->clock_ns * 0xffffff; - err++; - } - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { /* XXX check */ - if (cmd->stop_arg > 0x00ffffff) { - cmd->stop_arg = 0x00ffffff; - err++; - } - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + board->ao_speed); + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, + devpriv->clock_ns * 0xffffff); } + 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) + 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; @@ -3468,16 +3308,14 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (err) return 4; - /* step 5: fix up chanlist */ - - if (err) - return 5; - return 0; } static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + /* devpriv->ao0p=0x0000; */ /* ni_writew(devpriv->ao0p,AO_Configuration); */ @@ -3503,7 +3341,7 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->stc_writew(dev, devpriv->ao_mode1, AO_Mode_1_Register); devpriv->ao_mode2 = 0; devpriv->stc_writew(dev, devpriv->ao_mode2, AO_Mode_2_Register); - if (boardtype.reg_type & ni_reg_m_series_mask) + if (board->reg_type & ni_reg_m_series_mask) devpriv->ao_mode3 = AO_Last_Gate_Disable; else devpriv->ao_mode3 = 0; @@ -3511,12 +3349,11 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ao_trigger_select = 0; devpriv->stc_writew(dev, devpriv->ao_trigger_select, AO_Trigger_Select_Register); - if (boardtype.reg_type & ni_reg_6xxx_mask) { + if (board->reg_type & ni_reg_6xxx_mask) { unsigned immediate_bits = 0; unsigned i; - for (i = 0; i < s->n_chan; ++i) { + for (i = 0; i < s->n_chan; ++i) immediate_bits |= 1 << i; - } ao_win_out(immediate_bits, AO_Immediate_671x); ao_win_out(CLEAR_WG, AO_Misc_611x); } @@ -3529,63 +3366,44 @@ static int ni_ao_reset(struct comedi_device *dev, struct comedi_subdevice *s) static int ni_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { -#ifdef DEBUG_DIO - printk("ni_dio_insn_config() chan=%d io=%d\n", - CR_CHAN(insn->chanspec), data[0]); -#endif - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << CR_CHAN(insn->chanspec); - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << CR_CHAN(insn->chanspec)); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + struct ni_private *devpriv = dev->private; + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; devpriv->dio_control &= ~DIO_Pins_Dir_Mask; devpriv->dio_control |= DIO_Pins_Dir(s->io_bits); devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register); - return 1; + return insn->n; } static int ni_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { -#ifdef DEBUG_DIO - printk("ni_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], data[1]); -#endif - if (insn->n != 2) - return -EINVAL; - if (data[0]) { - /* Perform check to make sure we're not using the - serial part of the dio */ - if ((data[0] & (DIO_SDIN | DIO_SDOUT)) - && devpriv->serial_interval_ns) - return -EBUSY; - - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + struct ni_private *devpriv = dev->private; + + /* Make sure we're not using the serial part of the dio */ + if ((data[0] & (DIO_SDIN | DIO_SDOUT)) && devpriv->serial_interval_ns) + return -EBUSY; + + if (comedi_dio_update_state(s, data)) { devpriv->dio_output &= ~DIO_Parallel_Data_Mask; devpriv->dio_output |= DIO_Parallel_Data_Out(s->state); devpriv->stc_writew(dev, devpriv->dio_output, DIO_Output_Register); } + data[1] = devpriv->stc_readw(dev, DIO_Parallel_Input_Register); - return 2; + return insn->n; } static int ni_m_series_dio_insn_config(struct comedi_device *dev, @@ -3593,31 +3411,16 @@ static int ni_m_series_dio_insn_config(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { -#ifdef DEBUG_DIO - printk("ni_m_series_dio_insn_config() chan=%d io=%d\n", - CR_CHAN(insn->chanspec), data[0]); -#endif - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << CR_CHAN(insn->chanspec); - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << CR_CHAN(insn->chanspec)); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + struct ni_private *devpriv __maybe_unused = dev->private; + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; ni_writel(s->io_bits, M_Offset_DIO_Direction); - return 1; + return insn->n; } static int ni_m_series_dio_insn_bits(struct comedi_device *dev, @@ -3625,109 +3428,67 @@ static int ni_m_series_dio_insn_bits(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { -#ifdef DEBUG_DIO - printk("ni_m_series_dio_insn_bits() mask=0x%x bits=0x%x\n", data[0], - data[1]); -#endif - if (insn->n != 2) - return -EINVAL; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + struct ni_private *devpriv __maybe_unused = dev->private; + + if (comedi_dio_update_state(s, data)) ni_writel(s->state, M_Offset_Static_Digital_Output); - } + data[1] = ni_readl(M_Offset_Static_Digital_Input); - return 2; + return insn->n; } -static int ni_cdio_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int ni_cdio_check_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - int err = 0; - int tmp; - int sources; - unsigned i; + int i; - /* step 1: make sure trigger sources are trivially valid */ + for (i = 0; i < cmd->chanlist_len; ++i) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); - tmp = cmd->start_src; - sources = TRIG_INT; - cmd->start_src &= sources; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + if (chan != i) + return -EINVAL; + } - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + return 0; +} - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; +static int ni_cdio_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) +{ + int err = 0; + int tmp; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique... */ - - if (cmd->start_src != TRIG_INT) - err++; - if (cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_NONE) - err++; - /* ... and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ - if (cmd->start_src == TRIG_INT) { - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - } - if (cmd->scan_begin_src == TRIG_EXT) { - tmp = cmd->scan_begin_arg; - tmp &= CR_PACK_FLAGS(CDO_Sample_Source_Select_Mask, 0, 0, - CR_INVERT); - if (tmp != cmd->scan_begin_arg) { - err++; - } - } - if (cmd->convert_src == TRIG_NOW) { - if (cmd->convert_arg) { - cmd->convert_arg = 0; - err++; - } - } + /* Step 3: check if arguments are trivially valid */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->stop_src == TRIG_NONE) { - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + tmp = cmd->scan_begin_arg; + tmp &= CR_PACK_FLAGS(CDO_Sample_Source_Select_Mask, 0, 0, CR_INVERT); + if (tmp != cmd->scan_begin_arg) + err |= -EINVAL; + + 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; @@ -3737,12 +3498,9 @@ static int ni_cdio_cmdtest(struct comedi_device *dev, if (err) return 4; - /* step 5: check chanlist */ - - for (i = 0; i < cmd->chanlist_len; ++i) { - if (cmd->chanlist[i] != i) - err = 1; - } + /* Step 5: check channel list if it exists */ + if (cmd->chanlist && cmd->chanlist_len > 0) + err |= ni_cdio_check_chanlist(dev, s, cmd); if (err) return 5; @@ -3752,6 +3510,7 @@ static int ni_cdio_cmdtest(struct comedi_device *dev, static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct ni_private *devpriv __maybe_unused = dev->private; const struct comedi_cmd *cmd = &s->async->cmd; unsigned cdo_mode_bits = CDO_FIFO_Mode_Bit | CDO_Halt_On_Error_Bit; int retval; @@ -3780,27 +3539,34 @@ static int ni_cdio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return -EIO; } retval = ni_request_cdo_mite_channel(dev); - if (retval < 0) { + if (retval < 0) return retval; - } - s->async->inttrig = &ni_cdo_inttrig; + + s->async->inttrig = ni_cdo_inttrig; + return 0; } -static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int ni_cdo_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { #ifdef PCIDMA + struct ni_private *devpriv = dev->private; unsigned long flags; #endif + struct comedi_cmd *cmd = &s->async->cmd; int retval = 0; unsigned i; const unsigned timeout = 1000; + if (trig_num != cmd->start_arg) + return -EINVAL; + s->async->inttrig = NULL; /* read alloc the entire buffer */ - comedi_buf_read_alloc(s->async, s->async->prealloc_bufsz); + comedi_buf_read_alloc(s, s->async->prealloc_bufsz); #ifdef PCIDMA spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -3838,6 +3604,8 @@ static int ni_cdo_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, static int ni_cdio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct ni_private *devpriv __maybe_unused = dev->private; + ni_writel(CDO_Disarm_Bit | CDO_Error_Interrupt_Enable_Clear_Bit | CDO_Empty_FIFO_Interrupt_Enable_Clear_Bit | CDO_FIFO_Request_Interrupt_Enable_Clear_Bit, @@ -3853,15 +3621,16 @@ static int ni_cdio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) static void handle_cdio_interrupt(struct comedi_device *dev) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv __maybe_unused = dev->private; unsigned cdio_status; - struct comedi_subdevice *s = dev->subdevices + NI_DIO_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_DIO_SUBDEV]; #ifdef PCIDMA unsigned long flags; #endif - if ((boardtype.reg_type & ni_reg_m_series_mask) == 0) { + if ((board->reg_type & ni_reg_m_series_mask) == 0) return; - } #ifdef PCIDMA spin_lock_irqsave(&devpriv->mite_channel_lock, flags); if (devpriv->cdo_mite_chan) { @@ -3872,30 +3641,31 @@ static void handle_cdio_interrupt(struct comedi_device *dev) devpriv->mite->mite_io_addr + MITE_CHOR(devpriv->cdo_mite_chan->channel)); } - mite_sync_output_dma(devpriv->cdo_mite_chan, s->async); + mite_sync_output_dma(devpriv->cdo_mite_chan, s); } spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); #endif cdio_status = ni_readl(M_Offset_CDIO_Status); if (cdio_status & (CDO_Overrun_Bit | CDO_Underflow_Bit)) { -/* printk("cdio error: statux=0x%x\n", cdio_status); */ + /* printk("cdio error: statux=0x%x\n", cdio_status); */ ni_writel(CDO_Error_Interrupt_Confirm_Bit, M_Offset_CDIO_Command); /* XXX just guessing this is needed and does something useful */ s->async->events |= COMEDI_CB_OVERFLOW; } if (cdio_status & CDO_FIFO_Empty_Bit) { -/* printk("cdio fifo empty\n"); */ + /* printk("cdio fifo empty\n"); */ ni_writel(CDO_Empty_FIFO_Interrupt_Enable_Clear_Bit, M_Offset_CDIO_Command); -/* s->async->events |= COMEDI_CB_EOA; */ + /* s->async->events |= COMEDI_CB_EOA; */ } - ni_event(dev, s); + cfc_handle_events(dev, s); } static int ni_serial_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_private *devpriv = dev->private; int err = insn->n; unsigned char byte_out, byte_in = 0; @@ -3904,10 +3674,6 @@ static int ni_serial_insn_config(struct comedi_device *dev, switch (data[0]) { case INSN_CONFIG_SERIAL_CLOCK: - -#ifdef DEBUG_DIO - printk("SPI serial clock Config cd\n", data[1]); -#endif devpriv->serial_hw_mode = 1; devpriv->dio_control |= DIO_HW_Serial_Enable; @@ -3959,9 +3725,8 @@ static int ni_serial_insn_config(struct comedi_device *dev, case INSN_CONFIG_BIDIRECTIONAL_DATA: - if (devpriv->serial_interval_ns == 0) { + if (devpriv->serial_interval_ns == 0) return -EINVAL; - } byte_out = data[1] & 0xFF; @@ -3992,13 +3757,10 @@ static int ni_serial_hw_readwrite8(struct comedi_device *dev, unsigned char data_out, unsigned char *data_in) { + struct ni_private *devpriv = dev->private; unsigned int status1; int err = 0, count = 20; -#ifdef DEBUG_DIO - printk("ni_serial_hw_readwrite8: outputting 0x%x\n", data_out); -#endif - devpriv->dio_output &= ~DIO_Serial_Data_Mask; devpriv->dio_output |= DIO_Serial_Data_Out(data_out); devpriv->stc_writew(dev, devpriv->dio_output, DIO_Output_Register); @@ -4032,12 +3794,8 @@ static int ni_serial_hw_readwrite8(struct comedi_device *dev, DIO_Serial_IO_In_Progress_St goes high one bit too early. */ udelay((devpriv->serial_interval_ns + 999) / 1000); - if (data_in != NULL) { + if (data_in != NULL) *data_in = devpriv->stc_readw(dev, DIO_Serial_Input_Register); -#ifdef DEBUG_DIO - printk("ni_serial_hw_readwrite8: inputted 0x%x\n", *data_in); -#endif - } Error: devpriv->stc_writew(dev, devpriv->dio_control, DIO_Control_Register); @@ -4050,12 +3808,9 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev, unsigned char data_out, unsigned char *data_in) { + struct ni_private *devpriv = dev->private; unsigned char mask, input = 0; -#ifdef DEBUG_DIO - printk("ni_serial_sw_readwrite8: outputting 0x%x\n", data_out); -#endif - /* Wait for one bit before transfer */ udelay((devpriv->serial_interval_ns + 999) / 1000); @@ -4064,9 +3819,8 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev, because it is a per-subdevice field, and serial is a separate subdevice from DIO. */ devpriv->dio_output &= ~DIO_SDOUT; - if (data_out & mask) { + if (data_out & mask) devpriv->dio_output |= DIO_SDOUT; - } devpriv->stc_writew(dev, devpriv->dio_output, DIO_Output_Register); @@ -4086,15 +3840,12 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev, /* Input current bit */ if (devpriv->stc_readw(dev, - DIO_Parallel_Input_Register) & DIO_SDIN) - { -/* printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */ + DIO_Parallel_Input_Register) & DIO_SDIN) { + /* printk("DIO_P_I_R: 0x%x\n", devpriv->stc_readw(dev, DIO_Parallel_Input_Register)); */ input |= mask; } } -#ifdef DEBUG_DIO - printk("ni_serial_sw_readwrite8: inputted 0x%x\n", input); -#endif + if (data_in) *data_in = input; @@ -4103,13 +3854,12 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev, static void mio_common_detach(struct comedi_device *dev) { - if (dev->private) { - if (devpriv->counter_dev) { + struct ni_private *devpriv = dev->private; + + if (devpriv) { + if (devpriv->counter_dev) ni_gpct_device_destroy(devpriv->counter_dev); - } } - if (dev->subdevices && boardtype.has_8255) - subdev_8255_cleanup(dev, dev->subdevices + NI_8255_DIO_SUBDEV); } static void init_ao_67xx(struct comedi_device *dev, struct comedi_subdevice *s) @@ -4127,82 +3877,82 @@ static unsigned ni_gpct_to_stc_register(enum ni_gpct_register reg) { unsigned stc_register; switch (reg) { - case NITIO_G0_Autoincrement_Reg: + case NITIO_G0_AUTO_INC: stc_register = G_Autoincrement_Register(0); break; - case NITIO_G1_Autoincrement_Reg: + case NITIO_G1_AUTO_INC: stc_register = G_Autoincrement_Register(1); break; - case NITIO_G0_Command_Reg: + case NITIO_G0_CMD: stc_register = G_Command_Register(0); break; - case NITIO_G1_Command_Reg: + case NITIO_G1_CMD: stc_register = G_Command_Register(1); break; - case NITIO_G0_HW_Save_Reg: + case NITIO_G0_HW_SAVE: stc_register = G_HW_Save_Register(0); break; - case NITIO_G1_HW_Save_Reg: + case NITIO_G1_HW_SAVE: stc_register = G_HW_Save_Register(1); break; - case NITIO_G0_SW_Save_Reg: + case NITIO_G0_SW_SAVE: stc_register = G_Save_Register(0); break; - case NITIO_G1_SW_Save_Reg: + case NITIO_G1_SW_SAVE: stc_register = G_Save_Register(1); break; - case NITIO_G0_Mode_Reg: + case NITIO_G0_MODE: stc_register = G_Mode_Register(0); break; - case NITIO_G1_Mode_Reg: + case NITIO_G1_MODE: stc_register = G_Mode_Register(1); break; - case NITIO_G0_LoadA_Reg: + case NITIO_G0_LOADA: stc_register = G_Load_A_Register(0); break; - case NITIO_G1_LoadA_Reg: + case NITIO_G1_LOADA: stc_register = G_Load_A_Register(1); break; - case NITIO_G0_LoadB_Reg: + case NITIO_G0_LOADB: stc_register = G_Load_B_Register(0); break; - case NITIO_G1_LoadB_Reg: + case NITIO_G1_LOADB: stc_register = G_Load_B_Register(1); break; - case NITIO_G0_Input_Select_Reg: + case NITIO_G0_INPUT_SEL: stc_register = G_Input_Select_Register(0); break; - case NITIO_G1_Input_Select_Reg: + case NITIO_G1_INPUT_SEL: stc_register = G_Input_Select_Register(1); break; - case NITIO_G01_Status_Reg: + case NITIO_G01_STATUS: stc_register = G_Status_Register; break; - case NITIO_G01_Joint_Reset_Reg: + case NITIO_G01_RESET: stc_register = Joint_Reset_Register; break; - case NITIO_G01_Joint_Status1_Reg: + case NITIO_G01_STATUS1: stc_register = Joint_Status_1_Register; break; - case NITIO_G01_Joint_Status2_Reg: + case NITIO_G01_STATUS2: stc_register = Joint_Status_2_Register; break; - case NITIO_G0_Interrupt_Acknowledge_Reg: + case NITIO_G0_INT_ACK: stc_register = Interrupt_A_Ack_Register; break; - case NITIO_G1_Interrupt_Acknowledge_Reg: + case NITIO_G1_INT_ACK: stc_register = Interrupt_B_Ack_Register; break; - case NITIO_G0_Status_Reg: + case NITIO_G0_STATUS: stc_register = AI_Status_1_Register; break; - case NITIO_G1_Status_Reg: + case NITIO_G1_STATUS: stc_register = AO_Status_1_Register; break; - case NITIO_G0_Interrupt_Enable_Reg: + case NITIO_G0_INT_ENA: stc_register = Interrupt_A_Enable_Register; break; - case NITIO_G1_Interrupt_Enable_Reg: + case NITIO_G1_INT_ENA: stc_register = Interrupt_B_Enable_Register; break; default: @@ -4219,6 +3969,7 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg) { struct comedi_device *dev = counter->counter_dev->dev; + struct ni_private *devpriv = dev->private; unsigned stc_register; /* bits in the join reset register which are relevant to counters */ static const unsigned gpct_joint_reset_mask = G0_Reset | G1_Reset; @@ -4229,52 +3980,52 @@ static void ni_gpct_write_register(struct ni_gpct *counter, unsigned bits, switch (reg) { /* m-series-only registers */ - case NITIO_G0_Counting_Mode_Reg: + case NITIO_G0_CNT_MODE: ni_writew(bits, M_Offset_G0_Counting_Mode); break; - case NITIO_G1_Counting_Mode_Reg: + case NITIO_G1_CNT_MODE: ni_writew(bits, M_Offset_G1_Counting_Mode); break; - case NITIO_G0_Second_Gate_Reg: + case NITIO_G0_GATE2: ni_writew(bits, M_Offset_G0_Second_Gate); break; - case NITIO_G1_Second_Gate_Reg: + case NITIO_G1_GATE2: ni_writew(bits, M_Offset_G1_Second_Gate); break; - case NITIO_G0_DMA_Config_Reg: + case NITIO_G0_DMA_CFG: ni_writew(bits, M_Offset_G0_DMA_Config); break; - case NITIO_G1_DMA_Config_Reg: + case NITIO_G1_DMA_CFG: ni_writew(bits, M_Offset_G1_DMA_Config); break; - case NITIO_G0_ABZ_Reg: + case NITIO_G0_ABZ: ni_writew(bits, M_Offset_G0_MSeries_ABZ); break; - case NITIO_G1_ABZ_Reg: + case NITIO_G1_ABZ: ni_writew(bits, M_Offset_G1_MSeries_ABZ); break; /* 32 bit registers */ - case NITIO_G0_LoadA_Reg: - case NITIO_G1_LoadA_Reg: - case NITIO_G0_LoadB_Reg: - case NITIO_G1_LoadB_Reg: + case NITIO_G0_LOADA: + case NITIO_G1_LOADA: + case NITIO_G0_LOADB: + case NITIO_G1_LOADB: stc_register = ni_gpct_to_stc_register(reg); devpriv->stc_writel(dev, bits, stc_register); break; /* 16 bit registers */ - case NITIO_G0_Interrupt_Enable_Reg: + case NITIO_G0_INT_ENA: BUG_ON(bits & ~gpct_interrupt_a_enable_mask); ni_set_bitfield(dev, Interrupt_A_Enable_Register, gpct_interrupt_a_enable_mask, bits); break; - case NITIO_G1_Interrupt_Enable_Reg: + case NITIO_G1_INT_ENA: BUG_ON(bits & ~gpct_interrupt_b_enable_mask); ni_set_bitfield(dev, Interrupt_B_Enable_Register, gpct_interrupt_b_enable_mask, bits); break; - case NITIO_G01_Joint_Reset_Reg: + case NITIO_G01_RESET: BUG_ON(bits & ~gpct_joint_reset_mask); /* fall-through */ default: @@ -4287,24 +4038,23 @@ static unsigned ni_gpct_read_register(struct ni_gpct *counter, enum ni_gpct_register reg) { struct comedi_device *dev = counter->counter_dev->dev; + struct ni_private *devpriv = dev->private; unsigned stc_register; + switch (reg) { /* m-series only registers */ - case NITIO_G0_DMA_Status_Reg: + case NITIO_G0_DMA_STATUS: return ni_readw(M_Offset_G0_DMA_Status); - break; - case NITIO_G1_DMA_Status_Reg: + case NITIO_G1_DMA_STATUS: return ni_readw(M_Offset_G1_DMA_Status); - break; /* 32 bit registers */ - case NITIO_G0_HW_Save_Reg: - case NITIO_G1_HW_Save_Reg: - case NITIO_G0_SW_Save_Reg: - case NITIO_G1_SW_Save_Reg: + case NITIO_G0_HW_SAVE: + case NITIO_G1_HW_SAVE: + case NITIO_G0_SW_SAVE: + case NITIO_G1_SW_SAVE: stc_register = ni_gpct_to_stc_register(reg); return devpriv->stc_readl(dev, stc_register); - break; /* 16 bit registers */ default: @@ -4319,6 +4069,8 @@ static int ni_freq_out_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_private *devpriv = dev->private; + data[0] = devpriv->clock_and_fout & FOUT_Divider_mask; return 1; } @@ -4327,6 +4079,8 @@ static int ni_freq_out_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_private *devpriv = dev->private; + devpriv->clock_and_fout &= ~FOUT_Enable; devpriv->stc_writew(dev, devpriv->clock_and_fout, Clock_and_FOUT_Register); @@ -4341,6 +4095,8 @@ static int ni_freq_out_insn_write(struct comedi_device *dev, static int ni_set_freq_out_clock(struct comedi_device *dev, unsigned int clock_source) { + struct ni_private *devpriv = dev->private; + switch (clock_source) { case NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC: devpriv->clock_and_fout &= ~FOUT_Timebase_Select; @@ -4360,6 +4116,8 @@ static void ni_get_freq_out_clock(struct comedi_device *dev, unsigned int *clock_source, unsigned int *clock_period_ns) { + struct ni_private *devpriv = dev->private; + if (devpriv->clock_and_fout & FOUT_Timebase_Select) { *clock_source = NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC; *clock_period_ns = TIMEBASE_2_NS; @@ -4388,11 +4146,11 @@ static int ni_freq_out_insn_config(struct comedi_device *dev, static int ni_alloc_private(struct comedi_device *dev) { - int ret; + struct ni_private *devpriv; - ret = alloc_private(dev, sizeof(struct ni_private)); - if (ret < 0) - return ret; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; spin_lock_init(&devpriv->window_lock); spin_lock_init(&devpriv->soft_reg_copy_lock); @@ -4401,38 +4159,42 @@ static int ni_alloc_private(struct comedi_device *dev) return 0; }; -static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) +static int ni_E_init(struct comedi_device *dev) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; struct comedi_subdevice *s; unsigned j; enum ni_gpct_variant counter_variant; + int ret; - if (boardtype.n_aochan > MAX_N_AO_CHAN) { - printk("bug! boardtype.n_aochan > MAX_N_AO_CHAN\n"); + if (board->n_aochan > MAX_N_AO_CHAN) { + printk("bug! n_aochan > MAX_N_AO_CHAN\n"); return -EINVAL; } - if (alloc_subdevices(dev, NI_NUM_SUBDEVICES) < 0) - return -ENOMEM; + ret = comedi_alloc_subdevices(dev, NI_NUM_SUBDEVICES); + if (ret) + return ret; /* analog input subdevice */ - s = dev->subdevices + NI_AI_SUBDEV; + s = &dev->subdevices[NI_AI_SUBDEV]; dev->read_subdev = s; - if (boardtype.n_adchan) { + if (board->n_adchan) { s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_DITHER | SDF_CMD_READ; - if (boardtype.reg_type != ni_reg_611x) + if (board->reg_type != ni_reg_611x) s->subdev_flags |= SDF_GROUND | SDF_COMMON | SDF_OTHER; - if (boardtype.adbits > 16) + if (board->adbits > 16) s->subdev_flags |= SDF_LSAMPL; - if (boardtype.reg_type & ni_reg_m_series_mask) + if (board->reg_type & ni_reg_m_series_mask) s->subdev_flags |= SDF_SOFT_CALIBRATED; - s->n_chan = boardtype.n_adchan; + s->n_chan = board->n_adchan; s->len_chanlist = 512; - s->maxdata = (1 << boardtype.adbits) - 1; - s->range_table = ni_range_lkup[boardtype.gainlkup]; + s->maxdata = (1 << board->adbits) - 1; + s->range_table = ni_range_lkup[board->gainlkup]; s->insn_read = &ni_ai_insn_read; s->insn_config = &ni_ai_insn_config; s->do_cmdtest = &ni_ai_cmdtest; @@ -4449,55 +4211,54 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) /* analog output subdevice */ - s = dev->subdevices + NI_AO_SUBDEV; - if (boardtype.n_aochan) { + s = &dev->subdevices[NI_AO_SUBDEV]; + if (board->n_aochan) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_DEGLITCH | SDF_GROUND; - if (boardtype.reg_type & ni_reg_m_series_mask) + if (board->reg_type & ni_reg_m_series_mask) s->subdev_flags |= SDF_SOFT_CALIBRATED; - s->n_chan = boardtype.n_aochan; - s->maxdata = (1 << boardtype.aobits) - 1; - s->range_table = boardtype.ao_range_table; + s->n_chan = board->n_aochan; + s->maxdata = (1 << board->aobits) - 1; + s->range_table = board->ao_range_table; s->insn_read = &ni_ao_insn_read; - if (boardtype.reg_type & ni_reg_6xxx_mask) { + if (board->reg_type & ni_reg_6xxx_mask) s->insn_write = &ni_ao_insn_write_671x; - } else { + else s->insn_write = &ni_ao_insn_write; - } s->insn_config = &ni_ao_insn_config; #ifdef PCIDMA - if (boardtype.n_aochan) { + if (board->n_aochan) { s->async_dma_dir = DMA_TO_DEVICE; #else - if (boardtype.ao_fifo_depth) { + if (board->ao_fifo_depth) { #endif dev->write_subdev = s; s->subdev_flags |= SDF_CMD_WRITE; s->do_cmd = &ni_ao_cmd; s->do_cmdtest = &ni_ao_cmdtest; - s->len_chanlist = boardtype.n_aochan; - if ((boardtype.reg_type & ni_reg_m_series_mask) == 0) + s->len_chanlist = board->n_aochan; + if ((board->reg_type & ni_reg_m_series_mask) == 0) s->munge = ni_ao_munge; } s->cancel = &ni_ao_reset; } else { s->type = COMEDI_SUBD_UNUSED; } - if ((boardtype.reg_type & ni_reg_67xx_mask)) + if ((board->reg_type & ni_reg_67xx_mask)) init_ao_67xx(dev, s); /* digital i/o subdevice */ - s = dev->subdevices + NI_DIO_SUBDEV; + s = &dev->subdevices[NI_DIO_SUBDEV]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->maxdata = 1; s->io_bits = 0; /* all bits input */ s->range_table = &range_digital; - s->n_chan = boardtype.num_p0_dio_channels; - if (boardtype.reg_type & ni_reg_m_series_mask) { + s->n_chan = board->num_p0_dio_channels; + if (board->reg_type & ni_reg_m_series_mask) { s->subdev_flags |= - SDF_LSAMPL | SDF_CMD_WRITE /* | SDF_CMD_READ */ ; + SDF_LSAMPL | SDF_CMD_WRITE /* | SDF_CMD_READ */; s->insn_bits = &ni_m_series_dio_insn_bits; s->insn_config = &ni_m_series_dio_insn_config; s->do_cmd = &ni_cdio_cmd; @@ -4516,28 +4277,31 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* 8255 device */ - s = dev->subdevices + NI_8255_DIO_SUBDEV; - if (boardtype.has_8255) { - subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev); + s = &dev->subdevices[NI_8255_DIO_SUBDEV]; + if (board->has_8255) { + ret = subdev_8255_init(dev, s, ni_8255_callback, + (unsigned long)dev); + if (ret) + return ret; } else { s->type = COMEDI_SUBD_UNUSED; } /* formerly general purpose counter/timer device, but no longer used */ - s = dev->subdevices + NI_UNUSED_SUBDEV; + s = &dev->subdevices[NI_UNUSED_SUBDEV]; s->type = COMEDI_SUBD_UNUSED; /* calibration subdevice -- ai and ao */ - s = dev->subdevices + NI_CALIBRATION_SUBDEV; + s = &dev->subdevices[NI_CALIBRATION_SUBDEV]; s->type = COMEDI_SUBD_CALIB; - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { /* internal PWM analog output used for AI nonlinearity calibration */ s->subdev_flags = SDF_INTERNAL; s->insn_config = &ni_m_series_pwm_config; s->n_chan = 1; s->maxdata = 0; ni_writel(0x0, M_Offset_Cal_PWM); - } else if (boardtype.reg_type == ni_reg_6143) { + } else if (board->reg_type == ni_reg_6143) { /* internal PWM analog output used for AI nonlinearity calibration */ s->subdev_flags = SDF_INTERNAL; s->insn_config = &ni_6143_pwm_config; @@ -4551,11 +4315,11 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* EEPROM */ - s = dev->subdevices + NI_EEPROM_SUBDEV; + s = &dev->subdevices[NI_EEPROM_SUBDEV]; s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; s->maxdata = 0xff; - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { s->n_chan = M_SERIES_EEPROM_SIZE; s->insn_read = &ni_m_series_eeprom_insn_read; } else { @@ -4564,10 +4328,10 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* PFI */ - s = dev->subdevices + NI_PFI_DIO_SUBDEV; + s = &dev->subdevices[NI_PFI_DIO_SUBDEV]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { unsigned i; s->n_chan = 16; ni_writew(s->state, M_Offset_PFI_DO); @@ -4579,19 +4343,18 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) s->n_chan = 10; } s->maxdata = 1; - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) s->insn_bits = &ni_pfi_insn_bits; - } s->insn_config = &ni_pfi_insn_config; ni_set_bits(dev, IO_Bidirection_Pin_Register, ~0, 0); /* cs5529 calibration adc */ - s = dev->subdevices + NI_CS5529_CALIBRATION_SUBDEV; - if (boardtype.reg_type & ni_reg_67xx_mask) { + s = &dev->subdevices[NI_CS5529_CALIBRATION_SUBDEV]; + if (board->reg_type & ni_reg_67xx_mask) { s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL; /* one channel for each analog output channel */ - s->n_chan = boardtype.n_aochan; + s->n_chan = board->n_aochan; s->maxdata = (1 << 16) - 1; s->range_table = &range_unknown; /* XXX */ s->insn_read = cs5529_ai_insn_read; @@ -4602,7 +4365,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* Serial */ - s = dev->subdevices + NI_SERIAL_SUBDEV; + s = &dev->subdevices[NI_SERIAL_SUBDEV]; s->type = COMEDI_SUBD_SERIAL; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 1; @@ -4612,7 +4375,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->serial_hw_mode = 0; /* RTSI */ - s = dev->subdevices + NI_RTSI_SUBDEV; + s = &dev->subdevices[NI_RTSI_SUBDEV]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 8; @@ -4621,36 +4384,39 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_config = ni_rtsi_insn_config; ni_rtsi_init(dev); - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) counter_variant = ni_gpct_variant_m_series; - } else { + else counter_variant = ni_gpct_variant_e_series; - } devpriv->counter_dev = ni_gpct_device_construct(dev, &ni_gpct_write_register, &ni_gpct_read_register, counter_variant, NUM_GPCT); + if (!devpriv->counter_dev) + return -ENOMEM; + /* General purpose counters */ for (j = 0; j < NUM_GPCT; ++j) { - s = dev->subdevices + NI_GPCT_SUBDEV(j); + s = &dev->subdevices[NI_GPCT_SUBDEV(j)]; s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = - SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ - /* | SDF_CMD_WRITE */ ; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; s->n_chan = 3; - if (boardtype.reg_type & ni_reg_m_series_mask) + if (board->reg_type & ni_reg_m_series_mask) s->maxdata = 0xffffffff; else s->maxdata = 0xffffff; - s->insn_read = &ni_gpct_insn_read; - s->insn_write = &ni_gpct_insn_write; - s->insn_config = &ni_gpct_insn_config; + s->insn_read = ni_tio_insn_read; + s->insn_write = ni_tio_insn_read; + s->insn_config = ni_tio_insn_config; +#ifdef PCIDMA + s->subdev_flags |= SDF_CMD_READ /* | SDF_CMD_WRITE */; s->do_cmd = &ni_gpct_cmd; s->len_chanlist = 1; - s->do_cmdtest = &ni_gpct_cmdtest; + s->do_cmdtest = ni_tio_cmdtest; s->cancel = &ni_gpct_cancel; s->async_dma_dir = DMA_BIDIRECTIONAL; +#endif s->private = &devpriv->counter_dev->counters[j]; devpriv->counter_dev->counters[j].chip_index = 0; @@ -4659,7 +4425,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* Frequency output */ - s = dev->subdevices + NI_FREQ_OUT_SUBDEV; + s = &dev->subdevices[NI_FREQ_OUT_SUBDEV]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 1; @@ -4669,8 +4435,9 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_config = &ni_freq_out_insn_config; /* ai configuration */ - ni_ai_reset(dev, dev->subdevices + NI_AI_SUBDEV); - if ((boardtype.reg_type & ni_reg_6xxx_mask) == 0) { + s = &dev->subdevices[NI_AI_SUBDEV]; + ni_ai_reset(dev, s); + if ((board->reg_type & ni_reg_6xxx_mask) == 0) { /* BEAM is this needed for PCI-6143 ?? */ devpriv->clock_and_fout = Slow_Internal_Time_Divide_By_2 | @@ -4688,7 +4455,8 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) Clock_and_FOUT_Register); /* analog output configuration */ - ni_ao_reset(dev, dev->subdevices + NI_AO_SUBDEV); + s = &dev->subdevices[NI_AO_SUBDEV]; + ni_ao_reset(dev, s); if (dev->irq) { devpriv->stc_writew(dev, @@ -4706,11 +4474,11 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) ni_writeb(devpriv->ai_ao_select_reg, AI_AO_Select); ni_writeb(devpriv->g0_g1_select_reg, G0_G1_Select); - if (boardtype.reg_type & ni_reg_6xxx_mask) { + if (board->reg_type & ni_reg_6xxx_mask) { ni_writeb(0, Magic_611x); - } else if (boardtype.reg_type & ni_reg_m_series_mask) { + } else if (board->reg_type & ni_reg_m_series_mask) { int channel; - for (channel = 0; channel < boardtype.n_aochan; ++channel) { + for (channel = 0; channel < board->n_aochan; ++channel) { ni_writeb(0xf, M_Offset_AO_Waveform_Order(channel)); ni_writeb(0x0, M_Offset_AO_Reference_Attenuation(channel)); @@ -4718,13 +4486,13 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) ni_writeb(0x0, M_Offset_AO_Calibration); } - printk("\n"); return 0; } static int ni_8255_callback(int dir, int port, int data, unsigned long arg) { struct comedi_device *dev = (struct comedi_device *)arg; + struct ni_private *devpriv __maybe_unused = dev->private; if (dir) { ni_writeb(data, Port_A + 2 * port); @@ -4753,6 +4521,7 @@ static int ni_eeprom_insn_read(struct comedi_device *dev, static int ni_read_eeprom(struct comedi_device *dev, int addr) { + struct ni_private *devpriv __maybe_unused = dev->private; int bit; int bitstring; @@ -4780,6 +4549,8 @@ static int ni_m_series_eeprom_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { + struct ni_private *devpriv = dev->private; + data[0] = devpriv->eeprom_buffer[CR_CHAN(insn->chanspec)]; return 1; @@ -4787,6 +4558,8 @@ static int ni_m_series_eeprom_insn_read(struct comedi_device *dev, static int ni_get_pwm_config(struct comedi_device *dev, unsigned int *data) { + struct ni_private *devpriv = dev->private; + data[1] = devpriv->pwm_up_count * devpriv->clock_ns; data[2] = devpriv->pwm_down_count * devpriv->clock_ns; return 3; @@ -4796,7 +4569,9 @@ static int ni_m_series_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_private *devpriv = dev->private; unsigned up_count, down_count; + switch (data[0]) { case INSN_CONFIG_PWM_OUTPUT: switch (data[1]) { @@ -4862,7 +4637,9 @@ static int ni_6143_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_private *devpriv = dev->private; unsigned up_count, down_count; + switch (data[0]) { case INSN_CONFIG_PWM_OUTPUT: switch (data[1]) { @@ -4939,6 +4716,8 @@ static int ni_calib_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_private *devpriv = dev->private; + data[0] = devpriv->caldacs[CR_CHAN(insn->chanspec)]; return 1; @@ -4954,7 +4733,7 @@ static int pack_ad8842(int addr, int val, int *bitstring); struct caldac_struct { int n_chans; int n_bits; - int (*packbits) (int, int, int *); + int (*packbits)(int, int, int *); }; static struct caldac_struct caldacs[] = { @@ -4969,6 +4748,8 @@ static struct caldac_struct caldacs[] = { static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; int i, j; int n_dacs; int n_chans = 0; @@ -4977,12 +4758,12 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) int type; int chan; - type = boardtype.caldac[0]; + type = board->caldac[0]; if (type == caldac_none) return; n_bits = caldacs[type].n_bits; for (i = 0; i < 3; i++) { - type = boardtype.caldac[i]; + type = board->caldac[i]; if (type == caldac_none) break; if (caldacs[type].n_bits != n_bits) @@ -4995,13 +4776,12 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) if (diffbits) { unsigned int *maxdata_list; - if (n_chans > MAX_N_CALDACS) { + if (n_chans > MAX_N_CALDACS) printk("BUG! MAX_N_CALDACS too small\n"); - } s->maxdata_list = maxdata_list = devpriv->caldac_maxdata_list; chan = 0; for (i = 0; i < n_dacs; i++) { - type = boardtype.caldac[i]; + type = board->caldac[i]; for (j = 0; j < caldacs[type].n_chans; j++) { maxdata_list[chan] = (1 << caldacs[type].n_bits) - 1; @@ -5012,7 +4792,7 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) for (chan = 0; chan < s->n_chan; chan++) ni_write_caldac(dev, i, s->maxdata_list[i] / 2); } else { - type = boardtype.caldac[0]; + type = board->caldac[0]; s->maxdata = (1 << caldacs[type].n_bits) - 1; for (chan = 0; chan < s->n_chan; chan++) @@ -5022,6 +4802,8 @@ static void caldac_setup(struct comedi_device *dev, struct comedi_subdevice *s) static void ni_write_caldac(struct comedi_device *dev, int addr, int val) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; unsigned int loadbit = 0, bits = 0, bit, bitstring = 0; int i; int type; @@ -5032,7 +4814,7 @@ static void ni_write_caldac(struct comedi_device *dev, int addr, int val) devpriv->caldacs[addr] = val; for (i = 0; i < 3; i++) { - type = boardtype.caldac[i]; + type = board->caldac[i]; if (type == caldac_none) break; if (addr < caldacs[type].n_chans) { @@ -5192,36 +4974,11 @@ static void GPCT_Reset(struct comedi_device *dev, int chan) #endif -static int ni_gpct_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct ni_gpct *counter = s->private; - return ni_tio_insn_config(counter, insn, data); -} - -static int ni_gpct_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct ni_gpct *counter = s->private; - return ni_tio_rinsn(counter, insn, data); -} - -static int ni_gpct_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct ni_gpct *counter = s->private; - return ni_tio_winsn(counter, insn, data); -} - +#ifdef PCIDMA static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - int retval; -#ifdef PCIDMA struct ni_gpct *counter = s->private; -/* const struct comedi_cmd *cmd = &s->async->cmd; */ + int retval; retval = ni_request_gpct_mite_channel(dev, counter->counter_index, COMEDI_INPUT); @@ -5232,28 +4989,14 @@ static int ni_gpct_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL); ni_e_series_enable_second_irq(dev, counter->counter_index, 1); - retval = ni_tio_cmd(counter, s->async); -#else - retval = -ENOTSUPP; -#endif - return retval; -} - -static int ni_gpct_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ -#ifdef PCIDMA - struct ni_gpct *counter = s->private; - return ni_tio_cmdtest(counter, cmd); -#else - return -ENOTSUPP; -#endif + return ni_tio_cmd(dev, s); } +#endif +#ifdef PCIDMA static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { -#ifdef PCIDMA struct ni_gpct *counter = s->private; int retval; @@ -5261,10 +5004,8 @@ static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) ni_e_series_enable_second_irq(dev, counter->counter_index, 0); ni_release_gpct_mite_channel(dev, counter->counter_index); return retval; -#else - return 0; -#endif } +#endif /* * @@ -5275,8 +5016,10 @@ static int ni_gpct_cancel(struct comedi_device *dev, struct comedi_subdevice *s) static int ni_m_series_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { + struct ni_private *devpriv = dev->private; unsigned pfi_reg_index; unsigned array_offset; + if ((source & 0x1f) != source) return -EINVAL; pfi_reg_index = 1 + chan / 3; @@ -5302,7 +5045,9 @@ static int ni_old_set_pfi_routing(struct comedi_device *dev, unsigned chan, static int ni_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { - if (boardtype.reg_type & ni_reg_m_series_mask) + const struct ni_board_struct *board = comedi_board(dev); + + if (board->reg_type & ni_reg_m_series_mask) return ni_m_series_set_pfi_routing(dev, chan, source); else return ni_old_set_pfi_routing(dev, chan, source); @@ -5311,7 +5056,9 @@ static int ni_set_pfi_routing(struct comedi_device *dev, unsigned chan, static unsigned ni_m_series_get_pfi_routing(struct comedi_device *dev, unsigned chan) { + struct ni_private *devpriv = dev->private; const unsigned array_offset = chan / 3; + return MSeries_PFI_Output_Select_Source(chan, devpriv-> pfi_output_select_reg @@ -5361,7 +5108,9 @@ static unsigned ni_old_get_pfi_routing(struct comedi_device *dev, unsigned chan) static unsigned ni_get_pfi_routing(struct comedi_device *dev, unsigned chan) { - if (boardtype.reg_type & ni_reg_m_series_mask) + const struct ni_board_struct *board = comedi_board(dev); + + if (board->reg_type & ni_reg_m_series_mask) return ni_m_series_get_pfi_routing(dev, chan); else return ni_old_get_pfi_routing(dev, chan); @@ -5370,10 +5119,12 @@ static unsigned ni_get_pfi_routing(struct comedi_device *dev, unsigned chan) static int ni_config_filter(struct comedi_device *dev, unsigned pfi_channel, enum ni_pfi_filter_select filter) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv __maybe_unused = dev->private; unsigned bits; - if ((boardtype.reg_type & ni_reg_m_series_mask) == 0) { + + if ((board->reg_type & ni_reg_m_series_mask) == 0) return -ENOTSUPP; - } bits = ni_readl(M_Offset_PFI_Filter); bits &= ~MSeries_PFI_Filter_Select_Mask(pfi_channel); bits |= MSeries_PFI_Filter_Select_Bits(pfi_channel, filter); @@ -5383,24 +5134,28 @@ static int ni_config_filter(struct comedi_device *dev, unsigned pfi_channel, static int ni_pfi_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if ((boardtype.reg_type & ni_reg_m_series_mask) == 0) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv __maybe_unused = dev->private; + + if (!(board->reg_type & ni_reg_m_series_mask)) return -ENOTSUPP; - } - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + + if (comedi_dio_update_state(s, data)) ni_writew(s->state, M_Offset_PFI_DO); - } + data[1] = ni_readw(M_Offset_PFI_DI); - return 2; + + return insn->n; } static int ni_pfi_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct ni_private *devpriv = dev->private; unsigned int chan; if (insn->n < 1) @@ -5443,13 +5198,15 @@ static int ni_pfi_insn_config(struct comedi_device *dev, */ static void ni_rtsi_init(struct comedi_device *dev) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + /* Initialises the RTSI bus signal switch to a default state */ /* Set clock mode to internal */ devpriv->clock_and_fout2 = MSeries_RTSI_10MHz_Bit; - if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0) { + if (ni_set_master_clock(dev, NI_MIO_INTERNAL_CLOCK, 0) < 0) printk("ni_set_master_clock failed, bug?"); - } /* default internal lines routing to RTSI bus lines */ devpriv->rtsi_trig_a_output_reg = RTSI_Trig_Output_Bits(0, @@ -5467,7 +5224,7 @@ static void ni_rtsi_init(struct comedi_device *dev) RTSI_Trig_Output_Bits(5, NI_RTSI_OUTPUT_G_SRC0) | RTSI_Trig_Output_Bits(6, NI_RTSI_OUTPUT_G_GATE0); - if (boardtype.reg_type & ni_reg_m_series_mask) + if (board->reg_type & ni_reg_m_series_mask) devpriv->rtsi_trig_b_output_reg |= RTSI_Trig_Output_Bits(7, NI_RTSI_OUTPUT_RTSI_OSC); devpriv->stc_writew(dev, devpriv->rtsi_trig_b_output_reg, @@ -5483,12 +5240,9 @@ static int ni_rtsi_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - data[1] = 0; - return 2; + return insn->n; } /* Find best multiplier/divider to try and get the PLL running at 80 MHz @@ -5538,7 +5292,9 @@ static int ni_mseries_get_pll_parameters(unsigned reference_period_ns, static inline unsigned num_configurable_rtsi_channels(struct comedi_device *dev) { - if (boardtype.reg_type & ni_reg_m_series_mask) + const struct ni_board_struct *board = comedi_board(dev); + + if (board->reg_type & ni_reg_m_series_mask) return 8; else return 7; @@ -5547,6 +5303,7 @@ static inline unsigned num_configurable_rtsi_channels(struct comedi_device *dev) static int ni_mseries_set_pll_master_clock(struct comedi_device *dev, unsigned source, unsigned period_ns) { + struct ni_private *devpriv = dev->private; static const unsigned min_period_ns = 50; static const unsigned max_period_ns = 1000; static const unsigned timeout = 1000; @@ -5555,6 +5312,7 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device *dev, unsigned freq_multiplier; unsigned i; int retval; + if (source == NI_MIO_PLL_PXI10_CLOCK) period_ns = 100; /* these limits are somewhat arbitrary, but NI advertises 1 to 20MHz range so we'll use that */ @@ -5631,9 +5389,8 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device *dev, devpriv->clock_source = source; /* it seems to typically take a few hundred microseconds for PLL to lock */ for (i = 0; i < timeout; ++i) { - if (ni_readw(M_Offset_PLL_Status) & MSeries_PLL_Locked_Bit) { + if (ni_readw(M_Offset_PLL_Status) & MSeries_PLL_Locked_Bit) break; - } udelay(1); } if (i == timeout) { @@ -5648,12 +5405,15 @@ static int ni_mseries_set_pll_master_clock(struct comedi_device *dev, static int ni_set_master_clock(struct comedi_device *dev, unsigned source, unsigned period_ns) { + const struct ni_board_struct *board = comedi_board(dev); + struct ni_private *devpriv = dev->private; + if (source == NI_MIO_INTERNAL_CLOCK) { devpriv->rtsi_trig_direction_reg &= ~Use_RTSI_Clock_Bit; devpriv->stc_writew(dev, devpriv->rtsi_trig_direction_reg, RTSI_Trig_Direction_Register); devpriv->clock_ns = TIMEBASE_1_NS; - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { devpriv->clock_and_fout2 &= ~(MSeries_Timebase1_Select_Bit | MSeries_Timebase3_Select_Bit); @@ -5663,7 +5423,7 @@ static int ni_set_master_clock(struct comedi_device *dev, unsigned source, } devpriv->clock_source = source; } else { - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { return ni_mseries_set_pll_master_clock(dev, source, period_ns); } else { @@ -5693,6 +5453,8 @@ static int ni_set_master_clock(struct comedi_device *dev, unsigned source, static int ni_valid_rtsi_output_source(struct comedi_device *dev, unsigned chan, unsigned source) { + const struct ni_board_struct *board = comedi_board(dev); + if (chan >= num_configurable_rtsi_channels(dev)) { if (chan == old_RTSI_clock_channel) { if (source == NI_RTSI_OUTPUT_RTSI_OSC) @@ -5719,7 +5481,7 @@ static int ni_valid_rtsi_output_source(struct comedi_device *dev, unsigned chan, return 1; break; case NI_RTSI_OUTPUT_RTSI_OSC: - if (boardtype.reg_type & ni_reg_m_series_mask) + if (board->reg_type & ni_reg_m_series_mask) return 1; else return 0; @@ -5733,6 +5495,8 @@ static int ni_valid_rtsi_output_source(struct comedi_device *dev, unsigned chan, static int ni_set_rtsi_routing(struct comedi_device *dev, unsigned chan, unsigned source) { + struct ni_private *devpriv = dev->private; + if (ni_valid_rtsi_output_source(dev, chan, source) == 0) return -EINVAL; if (chan < 4) { @@ -5753,6 +5517,8 @@ static int ni_set_rtsi_routing(struct comedi_device *dev, unsigned chan, static unsigned ni_get_rtsi_routing(struct comedi_device *dev, unsigned chan) { + struct ni_private *devpriv = dev->private; + if (chan < 4) { return RTSI_Trig_Output_Source(chan, devpriv->rtsi_trig_a_output_reg); @@ -5771,15 +5537,16 @@ static int ni_rtsi_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); + struct ni_private *devpriv = dev->private; unsigned int chan = CR_CHAN(insn->chanspec); + switch (data[0]) { case INSN_CONFIG_DIO_OUTPUT: if (chan < num_configurable_rtsi_channels(dev)) { devpriv->rtsi_trig_direction_reg |= RTSI_Output_Bit(chan, - (boardtype. - reg_type & ni_reg_m_series_mask) != - 0); + (board->reg_type & ni_reg_m_series_mask) != 0); } else if (chan == old_RTSI_clock_channel) { devpriv->rtsi_trig_direction_reg |= Drive_RTSI_Clock_Bit; @@ -5791,9 +5558,7 @@ static int ni_rtsi_insn_config(struct comedi_device *dev, if (chan < num_configurable_rtsi_channels(dev)) { devpriv->rtsi_trig_direction_reg &= ~RTSI_Output_Bit(chan, - (boardtype. - reg_type & ni_reg_m_series_mask) - != 0); + (board->reg_type & ni_reg_m_series_mask) != 0); } else if (chan == old_RTSI_clock_channel) { devpriv->rtsi_trig_direction_reg &= ~Drive_RTSI_Clock_Bit; @@ -5806,10 +5571,9 @@ static int ni_rtsi_insn_config(struct comedi_device *dev, data[1] = (devpriv->rtsi_trig_direction_reg & RTSI_Output_Bit(chan, - (boardtype.reg_type & - ni_reg_m_series_mask) - != 0)) ? INSN_CONFIG_DIO_OUTPUT : - INSN_CONFIG_DIO_INPUT; + (board->reg_type & ni_reg_m_series_mask) != 0)) + ? INSN_CONFIG_DIO_OUTPUT + : INSN_CONFIG_DIO_INPUT; } else if (chan == old_RTSI_clock_channel) { data[1] = (devpriv->rtsi_trig_direction_reg & @@ -5848,13 +5612,11 @@ static int cs5529_wait_for_idle(struct comedi_device *dev) for (i = 0; i < timeout; i++) { status = ni_ao_win_inw(dev, CAL_ADC_Status_67xx); - if ((status & CSS_ADC_BUSY) == 0) { + if ((status & CSS_ADC_BUSY) == 0) break; - } set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout(1)) { + if (schedule_timeout(1)) return -EIO; - } } /* printk("looped %i times waiting for idle\n", i); */ if (i == timeout) { @@ -5880,9 +5642,8 @@ static void cs5529_command(struct comedi_device *dev, unsigned short value) udelay(1); } /* printk("looped %i times writing command to cs5529\n", i); */ - if (i == timeout) { + if (i == timeout) comedi_error(dev, "possible problem - never saw adc go busy?"); - } } /* write to cs5529 register */ @@ -5899,25 +5660,6 @@ static void cs5529_config_write(struct comedi_device *dev, unsigned int value, comedi_error(dev, "time or signal in cs5529_config_write()"); } -#ifdef NI_CS5529_DEBUG -/* read from cs5529 register */ -static unsigned int cs5529_config_read(struct comedi_device *dev, - unsigned int reg_select_bits) -{ - unsigned int value; - - reg_select_bits &= CSCMD_REGISTER_SELECT_MASK; - cs5529_command(dev, CSCMD_COMMAND | CSCMD_READ | reg_select_bits); - if (cs5529_wait_for_idle(dev)) - comedi_error(dev, "timeout or signal in cs5529_config_read()"); - value = (ni_ao_win_inw(dev, - CAL_ADC_Config_Data_High_Word_67xx) << 16) & - 0xff0000; - value |= ni_ao_win_inw(dev, CAL_ADC_Config_Data_Low_Word_67xx) & 0xffff; - return value; -} -#endif - static int cs5529_do_conversion(struct comedi_device *dev, unsigned short *data) { int retval; @@ -5994,12 +5736,5 @@ static int init_cs5529(struct comedi_device *dev) if (cs5529_wait_for_idle(dev)) comedi_error(dev, "timeout or signal in init_cs5529()\n"); #endif -#ifdef NI_CS5529_DEBUG - printk("config: 0x%x\n", cs5529_config_read(dev, - CSCMD_CONFIG_REGISTER)); - printk("gain: 0x%x\n", cs5529_config_read(dev, CSCMD_GAIN_REGISTER)); - printk("offset: 0x%x\n", cs5529_config_read(dev, - CSCMD_OFFSET_REGISTER)); -#endif return 0; } diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index 53ec24bb6dc..de421486b75 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_mio_cs @@ -41,6 +36,7 @@ See the notes in the ni_atmio.o driver. */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> @@ -51,8 +47,6 @@ See the notes in the ni_atmio.o driver. #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> -#undef DEBUG - #define ATMIO 1 #undef PCIMIO @@ -65,119 +59,95 @@ See the notes in the ni_atmio.o driver. #define MAX_N_CALDACS 32 static const struct ni_board_struct ni_boards[] = { - {.device_id = 0x010d, - .name = "DAQCard-ai-16xe-50", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 1024, - .alwaysdither = 0, - .gainlkup = ai_gain_8, - .ai_speed = 5000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {dac8800, dac8043}, - }, - {.device_id = 0x010c, - .name = "DAQCard-ai-16e-4", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 1024, - .alwaysdither = 0, - .gainlkup = ai_gain_16, - .ai_speed = 4000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {mb88341}, /* verified */ - }, - {.device_id = 0x02c4, - .name = "DAQCard-6062E", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 8192, - .alwaysdither = 0, - .gainlkup = ai_gain_16, - .ai_speed = 2000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 2048, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 1176, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {ad8804_debug}, /* verified */ - }, - {.device_id = 0x075e, - .name = "DAQCard-6024E", /* specs incorrect! */ - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 1024, - .alwaysdither = 0, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 1000000, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {ad8804_debug}, - }, - {.device_id = 0x0245, - .name = "DAQCard-6036E", /* specs incorrect! */ - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 1024, - .alwaysdither = 1, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 1000000, - .num_p0_dio_channels = 8, - .has_8255 = 0, - .caldac = {ad8804_debug}, + { + .device_id = 0x010d, + .name = "DAQCard-ai-16xe-50", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 1024, + .gainlkup = ai_gain_8, + .ai_speed = 5000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043 }, + }, { + .device_id = 0x010c, + .name = "DAQCard-ai-16e-4", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 1024, + .gainlkup = ai_gain_16, + .ai_speed = 4000, + .num_p0_dio_channels = 8, + .caldac = { mb88341 }, /* verified */ + }, { + .device_id = 0x02c4, + .name = "DAQCard-6062E", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 8192, + .gainlkup = ai_gain_16, + .ai_speed = 2000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, + .ao_range_table = &range_bipolar10, + .ao_speed = 1176, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, /* verified */ + }, { + /* specs incorrect! */ + .device_id = 0x075e, + .name = "DAQCard-6024E", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 1024, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 12, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, { + /* specs incorrect! */ + .device_id = 0x0245, + .name = "DAQCard-6036E", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 1024, + .alwaysdither = 1, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 16, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, }, #if 0 - {.device_id = 0x0000, /* unknown */ - .name = "DAQCard-6715", - .n_adchan = 0, - .n_aochan = 8, - .aobits = 12, - .ao_671x = 8192, - .num_p0_dio_channels = 8, - .caldac = {mb88341, mb88341}, - }, + { + .device_id = 0x0000, /* unknown */ + .name = "DAQCard-6715", + .n_aochan = 8, + .aobits = 12, + .ao_671x = 8192, + .num_p0_dio_channels = 8, + .caldac = { mb88341, mb88341 }, + }, #endif - /* N.B. Update ni_mio_cs_ids[] when entries added above. */ }; #define interrupt_pin(a) 0 #define IRQ_POLARITY 1 -#define NI_E_IRQ_FLAGS IRQF_SHARED - struct ni_private { struct pcmcia_device *link; - NI_PRIVATE_COMMON}; - -#define devpriv ((struct ni_private *)dev->private) +NI_PRIVATE_COMMON}; /* How we access registers */ @@ -196,6 +166,7 @@ struct ni_private { static void mio_cs_win_out(struct comedi_device *dev, uint16_t data, int addr) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->window_lock, flags); @@ -210,6 +181,7 @@ static void mio_cs_win_out(struct comedi_device *dev, uint16_t data, int addr) static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr) { + struct ni_private *devpriv = dev->private; unsigned long flags; uint16_t ret; @@ -225,76 +197,22 @@ static uint16_t mio_cs_win_in(struct comedi_device *dev, int addr) return ret; } -static int mio_cs_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int mio_cs_detach(struct comedi_device *dev); -static struct comedi_driver driver_ni_mio_cs = { - .driver_name = "ni_mio_cs", - .module = THIS_MODULE, - .attach = mio_cs_attach, - .detach = mio_cs_detach, -}; - #include "ni_mio_common.c" -static int ni_getboardtype(struct comedi_device *dev, - struct pcmcia_device *link); - -/* clean up allocated resources */ -/* called when driver is removed */ -static int mio_cs_detach(struct comedi_device *dev) -{ - mio_common_detach(dev); - - /* PCMCIA layer frees the IO region */ - - if (dev->irq) - free_irq(dev->irq, dev); - - return 0; -} - -static void mio_cs_config(struct pcmcia_device *link); -static void cs_release(struct pcmcia_device *link); -static void cs_detach(struct pcmcia_device *); - -static struct pcmcia_device *cur_dev = NULL; - -static int cs_attach(struct pcmcia_device *link) -{ - cur_dev = link; - - mio_cs_config(link); - - return 0; -} - -static void cs_release(struct pcmcia_device *link) -{ - pcmcia_disable_device(link); -} - -static void cs_detach(struct pcmcia_device *link) -{ - DPRINTK("cs_detach(link=%p)\n", link); - - cs_release(link); -} - -static int mio_cs_suspend(struct pcmcia_device *link) +static const void *ni_getboardtype(struct comedi_device *dev, + struct pcmcia_device *link) { - DPRINTK("pm suspend\n"); - - return 0; -} + static const struct ni_board_struct *board; + int i; -static int mio_cs_resume(struct pcmcia_device *link) -{ - DPRINTK("pm resume\n"); - return 0; + for (i = 0; i < ARRAY_SIZE(ni_boards); i++) { + board = &ni_boards[i]; + if (board->device_id == link->card_id) + return board; + } + return NULL; } - static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) { int base, ret; @@ -311,111 +229,63 @@ static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) return -ENODEV; } - -static void mio_cs_config(struct pcmcia_device *link) -{ - int ret; - - DPRINTK("mio_cs_config(link=%p)\n", link); - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; - - ret = pcmcia_loop_config(link, mio_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - return; - } - - if (!link->irq) - dev_info(&link->dev, "no IRQ available\n"); - - ret = pcmcia_enable_device(link); -} - -static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int mio_cs_auto_attach(struct comedi_device *dev, + unsigned long context) { - struct pcmcia_device *link; - unsigned int irq; + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + static const struct ni_board_struct *board; + struct ni_private *devpriv; int ret; - DPRINTK("mio_cs_attach(dev=%p,it=%p)\n", dev, it); - - link = cur_dev; /* XXX hack */ - if (!link) - return -EIO; + board = ni_getboardtype(dev, link); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; - dev->driver = &driver_ni_mio_cs; + link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + ret = comedi_pcmcia_enable(dev, mio_pcmcia_config_loop); + if (ret) + return ret; dev->iobase = link->resource[0]->start; - irq = link->irq; - - printk("comedi%d: %s: DAQCard: io 0x%04lx, irq %u, ", - dev->minor, dev->driver->driver_name, dev->iobase, irq); - -#if 0 - { - int i; - - printk(" board fingerprint:"); - for (i = 0; i < 32; i += 2) { - printk(" %04x %02x", inw(dev->iobase + i), - inb(dev->iobase + i + 1)); - } - printk("\n"); - printk(" board fingerprint (windowed):"); - for (i = 0; i < 10; i++) - printk(" 0x%04x", win_in(i)); - printk("\n"); - } -#endif - - dev->board_ptr = ni_boards + ni_getboardtype(dev, link); - - printk(" %s", boardtype.name); - dev->board_name = boardtype.name; - - ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, - "ni_mio_cs", dev); - if (ret < 0) { - printk(" irq not available\n"); - return -EINVAL; - } - dev->irq = irq; + link->priv = dev; + ret = pcmcia_request_irq(link, ni_E_interrupt); + if (ret) + return ret; + dev->irq = link->irq; - /* allocate private area */ ret = ni_alloc_private(dev); - if (ret < 0) + if (ret) return ret; - devpriv->stc_writew = &mio_cs_win_out; - devpriv->stc_readw = &mio_cs_win_in; - devpriv->stc_writel = &win_out2; - devpriv->stc_readl = &win_in2; - - ret = ni_E_init(dev, it); + devpriv = dev->private; + devpriv->stc_writew = mio_cs_win_out; + devpriv->stc_readw = mio_cs_win_in; + devpriv->stc_writel = win_out2; + devpriv->stc_readl = win_in2; - if (ret < 0) - return ret; - - return 0; + return ni_E_init(dev); } -static int ni_getboardtype(struct comedi_device *dev, - struct pcmcia_device *link) +static void mio_cs_detach(struct comedi_device *dev) { - int i; - - for (i = 0; i < n_ni_boards; i++) { - if (ni_boards[i].device_id == link->card_id) - return i; - } + mio_common_detach(dev); + comedi_pcmcia_disable(dev); +} - printk("unknown board 0x%04x -- pretend it is a ", link->card_id); +static struct comedi_driver driver_ni_mio_cs = { + .driver_name = "ni_mio_cs", + .module = THIS_MODULE, + .auto_attach = mio_cs_auto_attach, + .detach = mio_cs_detach, +}; - return 0; +static int cs_attach(struct pcmcia_device *link) +{ + return comedi_pcmcia_auto_config(link, &driver_ni_mio_cs); } -#ifdef MODULE - static const struct pcmcia_device_id ni_mio_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010d), /* DAQCard-ai-16xe-50 */ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010c), /* DAQCard-ai-16e-4 */ @@ -424,36 +294,17 @@ static const struct pcmcia_device_id ni_mio_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0245), /* DAQCard-6036E */ PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, ni_mio_cs_ids); -MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); -MODULE_DESCRIPTION("Comedi driver for National Instruments DAQCard E series"); -MODULE_LICENSE("GPL"); -struct pcmcia_driver ni_mio_cs_driver = { - .probe = &cs_attach, - .remove = &cs_detach, - .suspend = &mio_cs_suspend, - .resume = &mio_cs_resume, - .id_table = ni_mio_cs_ids, - .owner = THIS_MODULE, - .name = "ni_mio_cs", +static struct pcmcia_driver ni_mio_cs_driver = { + .name = "ni_mio_cs", + .owner = THIS_MODULE, + .id_table = ni_mio_cs_ids, + .probe = cs_attach, + .remove = comedi_pcmcia_auto_unconfig, }; +module_comedi_pcmcia_driver(driver_ni_mio_cs, ni_mio_cs_driver); -int init_module(void) -{ - pcmcia_register_driver(&ni_mio_cs_driver); - comedi_driver_register(&driver_ni_mio_cs); - return 0; -} - -void cleanup_module(void) -{ - pcmcia_unregister_driver(&ni_mio_cs_driver); -#if 0 - while (cur_dev != NULL) - cs_detach(cur_dev->handle); -#endif - comedi_driver_unregister(&driver_ni_mio_cs); -} -#endif +MODULE_DESCRIPTION("Comedi driver for National Instruments DAQCard E series"); +MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 8dd3a01d48d..5fc74d6ff6a 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -1,8 +1,6 @@ /* comedi/drivers/ni_pcidio.c - driver for National Instruments PCI-DIO-96/PCI-6508 - National Instruments PCI-DIO-32HS - National Instruments PCI-6503 + driver for National Instruments PCI-DIO-32HS COMEDI - Linux Control and Measurement Device Interface Copyright (C) 1999,2002 David A. Schleef <ds@schleef.org> @@ -16,24 +14,16 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ni_pcidio -Description: National Instruments PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 +Description: National Instruments PCI-DIO32HS, PCI-6533 Author: ds Status: works -Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio), PXI-6533, - PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X, - PXI-6503, PCI-6533, PCI-6534 -Updated: Sun, 21 Apr 2002 21:03:38 -0700 - -The DIO-96 appears as four 8255 subdevices. See the 8255 -driver notes for details. +Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio) + [National Instruments] PXI-6533, PCI-6533 (pxi-6533) + [National Instruments] PCI-6534 (pci-6534) +Updated: Mon, 09 Jan 2012 14:27:23 +0000 The DIO32HS board appears as one subdevice, with 32 channels. Each channel is individually I/O configurable. The channel order @@ -42,6 +32,11 @@ supports simple digital I/O; no handshaking is supported. DMA mostly works for the PCI-DIO32HS, but only in timed input mode. +The PCI-DIO-32HS/PCI-6533 has a configurable external trigger. Setting +scan_begin_arg to 0 or CR_EDGE triggers on the leading edge. Setting +scan_begin_arg to CR_INVERT or (CR_EDGE | CR_INVERT) triggers on the +trailing edge. + This driver could be easily modified to support AT-MIO32HS and AT-MIO96. @@ -51,49 +46,21 @@ it are contained in the comedi_nonfree_firmware tarball available from http://www.comedi.org */ -/* - This driver is for both the NI PCI-DIO-32HS and the PCI-DIO-96, - which have very different architectures. But, since the '96 is - so simple, it is included here. - - Manuals (available from ftp://ftp.natinst.com/support/manuals) - - 320938c.pdf PCI-DIO-96/PXI-6508/PCI-6503 User Manual - 321464b.pdf AT/PCI-DIO-32HS User Manual - 341329A.pdf PCI-6533 Register-Level Programmer Manual - 341330A.pdf DAQ-DIO Technical Reference Manual - - */ - #define USE_DMA -/* #define DEBUG 1 */ -/* #define DEBUG_FLAGS */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include <linux/sched.h> + #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" -#include "8255.h" - -#undef DPRINTK -#ifdef DEBUG -#define DPRINTK(format, args...) printk(format, ## args) -#else -#define DPRINTK(format, args...) -#endif #define PCI_DIO_SIZE 4096 #define PCI_MITE_SIZE 4096 -/* defines for the PCI-DIO-96 */ - -#define NIDIO_8255_BASE(x) ((x)*4) -#define NIDIO_A 0 -#define NIDIO_B 4 -#define NIDIO_C 8 -#define NIDIO_D 12 - /* defines for the PCI-DIO-32HS */ #define Window_Address 4 /* W */ @@ -253,6 +220,14 @@ static inline unsigned secondary_DMAChannel_bits(unsigned channel) #define Protocol_Register_8 88 /* 32 bit */ #define StartDelay Protocol_Register_8 +/* Firmware files for PCI-6524 */ +#define FW_PCI_6534_MAIN "ni6534a.bin" +#define FW_PCI_6534_SCARAB_DI "niscrb01.bin" +#define FW_PCI_6534_SCARAB_DO "niscrb02.bin" +MODULE_FIRMWARE(FW_PCI_6534_MAIN); +MODULE_FIRMWARE(FW_PCI_6534_SCARAB_DI); +MODULE_FIRMWARE(FW_PCI_6534_SCARAB_DO); + enum pci_6534_firmware_registers { /* 16 bit */ Firmware_Control_Register = 0x100, Firmware_Status_Register = 0x104, @@ -288,110 +263,30 @@ enum FPGA_Control_Bits { #define IntEn (TransferReady|CountExpired|Waited|PrimaryTC|SecondaryTC) #endif -static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int nidio_detach(struct comedi_device *dev); -static int ni_pcidio_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); - -static struct comedi_driver driver_pcidio = { - .driver_name = "ni_pcidio", - .module = THIS_MODULE, - .attach = nidio_attach, - .detach = nidio_detach, +enum nidio_boardid { + BOARD_PCIDIO_32HS, + BOARD_PXI6533, + BOARD_PCI6534, }; struct nidio_board { - - int dev_id; const char *name; - int n_8255; - unsigned int is_diodaq:1; unsigned int uses_firmware:1; }; static const struct nidio_board nidio_boards[] = { - { - .dev_id = 0x1150, - .name = "pci-dio-32hs", - .n_8255 = 0, - .is_diodaq = 1, - }, - { - .dev_id = 0x1320, - .name = "pxi-6533", - .n_8255 = 0, - .is_diodaq = 1, - }, - { - .dev_id = 0x12b0, - .name = "pci-6534", - .n_8255 = 0, - .is_diodaq = 1, - .uses_firmware = 1, - }, - { - .dev_id = 0x0160, - .name = "pci-dio-96", - .n_8255 = 4, - .is_diodaq = 0, - }, - { - .dev_id = 0x1630, - .name = "pci-dio-96b", - .n_8255 = 4, - .is_diodaq = 0, - }, - { - .dev_id = 0x13c0, - .name = "pxi-6508", - .n_8255 = 4, - .is_diodaq = 0, - }, - { - .dev_id = 0x0400, - .name = "pci-6503", - .n_8255 = 1, - .is_diodaq = 0, - }, - { - .dev_id = 0x1250, - .name = "pci-6503b", - .n_8255 = 1, - .is_diodaq = 0, - }, - { - .dev_id = 0x17d0, - .name = "pci-6503x", - .n_8255 = 1, - .is_diodaq = 0, - }, - { - .dev_id = 0x1800, - .name = "pxi-6503", - .n_8255 = 1, - .is_diodaq = 0, - }, + [BOARD_PCIDIO_32HS] = { + .name = "pci-dio-32hs", + }, + [BOARD_PXI6533] = { + .name = "pxi-6533", + }, + [BOARD_PCI6534] = { + .name = "pci-6534", + .uses_firmware = 1, + }, }; -#define n_nidio_boards ARRAY_SIZE(nidio_boards) -#define this_board ((const struct nidio_board *)dev->board_ptr) - -static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table); - struct nidio96_private { struct mite_struct *mite; int boardtype; @@ -401,7 +296,6 @@ struct nidio96_private { struct mite_dma_descriptor_ring *di_mite_ring; spinlock_t mite_channel_lock; }; -#define devpriv ((struct nidio96_private *)dev->private) static int ni_pcidio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, @@ -409,21 +303,13 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev, static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); static int ni_pcidio_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum); -static int nidio_find_device(struct comedi_device *dev, int bus, int slot); static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode); static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s); -#ifdef DEBUG_FLAGS -static void ni_pcidio_print_flags(unsigned int flags); -static void ni_pcidio_print_status(unsigned int status); -#else -#define ni_pcidio_print_flags(x) -#define ni_pcidio_print_status(x) -#endif - static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev) { + struct nidio96_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -436,6 +322,7 @@ static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev) comedi_error(dev, "failed to reserve mite dma channel."); return -EBUSY; } + devpriv->di_mite_chan->dir = COMEDI_INPUT; writeb(primary_DMAChannel_bits(devpriv->di_mite_chan->channel) | secondary_DMAChannel_bits(devpriv->di_mite_chan->channel), devpriv->mite->daq_io_addr + DMA_Line_Control_Group1); @@ -446,6 +333,7 @@ static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev) static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) { + struct nidio96_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -462,93 +350,78 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } -static int nidio96_8255_cb(int dir, int port, int data, unsigned long iobase) +static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s) { - if (dir) { - writeb(data, (void *)(iobase + port)); - return 0; - } else { - return readb((void *)(iobase + port)); - } -} + struct nidio96_private *devpriv = dev->private; + unsigned long irq_flags; + int count; -void ni_pcidio_event(struct comedi_device *dev, struct comedi_subdevice *s) -{ - if (s-> - async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | - COMEDI_CB_OVERFLOW)) { - ni_pcidio_cancel(dev, s); - } - comedi_event(dev, s); + spin_lock_irqsave(&dev->spinlock, irq_flags); + spin_lock(&devpriv->mite_channel_lock); + if (devpriv->di_mite_chan) + mite_sync_input_dma(devpriv->di_mite_chan, s); + spin_unlock(&devpriv->mite_channel_lock); + count = s->async->buf_write_count - s->async->buf_read_count; + spin_unlock_irqrestore(&dev->spinlock, irq_flags); + return count; } static irqreturn_t nidio_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices; + struct nidio96_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async = s->async; struct mite_struct *mite = devpriv->mite; /* int i, j; */ - long int AuxData = 0; - short data1 = 0; - short data2 = 0; + unsigned int auxdata = 0; + unsigned short data1 = 0; + unsigned short data2 = 0; int flags; int status; int work = 0; unsigned int m_status = 0; - unsigned long irq_flags; /* interrupcions parasites */ - if (dev->attached == 0) { + if (!dev->attached) { /* assume it's from another card */ return IRQ_NONE; } + /* Lock to avoid race with comedi_poll */ + spin_lock(&dev->spinlock); + status = readb(devpriv->mite->daq_io_addr + Interrupt_And_Window_Status); flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); - DPRINTK("ni_pcidio_interrupt: status=0x%02x,flags=0x%02x\n", - status, flags); - ni_pcidio_print_flags(flags); - ni_pcidio_print_status(status); - - /* printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); */ - /* printk("buf[4096]=%08x\n", - *(unsigned int *)(async->prealloc_buf+4096)); */ - - spin_lock_irqsave(&devpriv->mite_channel_lock, irq_flags); + spin_lock(&devpriv->mite_channel_lock); if (devpriv->di_mite_chan) m_status = mite_get_status(devpriv->di_mite_chan); -#ifdef MITE_DEBUG - mite_print_chsr(m_status); -#endif - /* printk("mite_bytes_transferred: %d\n", - mite_bytes_transferred(mite,DI_DMA_CHAN)); */ - /* mite_dump_regs(mite); */ if (m_status & CHSR_INT) { if (m_status & CHSR_LINKC) { writel(CHOR_CLRLC, mite->mite_io_addr + MITE_CHOR(devpriv->di_mite_chan->channel)); - mite_sync_input_dma(devpriv->di_mite_chan, s->async); + mite_sync_input_dma(devpriv->di_mite_chan, s); /* XXX need to byteswap */ } if (m_status & ~(CHSR_INT | CHSR_LINKC | CHSR_DONE | CHSR_DRDY | CHSR_DRQ1 | CHSR_MRDY)) { - DPRINTK("unknown mite interrupt, disabling IRQ\n"); + dev_dbg(dev->class_dev, + "unknown mite interrupt, disabling IRQ\n"); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; disable_irq(dev->irq); } } - spin_unlock_irqrestore(&devpriv->mite_channel_lock, irq_flags); + spin_unlock(&devpriv->mite_channel_lock); while (status & DataLeft) { work++; if (work > 20) { - DPRINTK("too much work in interrupt\n"); + dev_dbg(dev->class_dev, "too much work in interrupt\n"); writeb(0x00, devpriv->mite->daq_io_addr + Master_DMA_And_Interrupt_Control); @@ -558,39 +431,31 @@ static irqreturn_t nidio_interrupt(int irq, void *d) flags &= IntEn; if (flags & TransferReady) { - /* DPRINTK("TransferReady\n"); */ while (flags & TransferReady) { work++; if (work > 100) { - DPRINTK("too much work in interrupt\n"); + dev_dbg(dev->class_dev, + "too much work in interrupt\n"); writeb(0x00, devpriv->mite->daq_io_addr + Master_DMA_And_Interrupt_Control ); goto out; } - AuxData = + auxdata = readl(devpriv->mite->daq_io_addr + Group_1_FIFO); - data1 = AuxData & 0xffff; - data2 = (AuxData & 0xffff0000) >> 16; - comedi_buf_put(async, data1); - comedi_buf_put(async, data2); - /* DPRINTK("read:%d, %d\n",data1,data2); */ + data1 = auxdata & 0xffff; + data2 = (auxdata & 0xffff0000) >> 16; + comedi_buf_put(s, data1); + comedi_buf_put(s, data2); flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); } - /* DPRINTK("buf_int_count: %d\n", - async->buf_int_count); */ - /* DPRINTK("1) IntEn=%d,flags=%d,status=%d\n", - IntEn,flags,status); */ - /* ni_pcidio_print_flags(flags); */ - /* ni_pcidio_print_status(status); */ async->events |= COMEDI_CB_BLOCK; } if (flags & CountExpired) { - DPRINTK("CountExpired\n"); writeb(ClearExpired, devpriv->mite->daq_io_addr + Group_1_Second_Clear); @@ -599,45 +464,30 @@ static irqreturn_t nidio_interrupt(int irq, void *d) writeb(0x00, devpriv->mite->daq_io_addr + OpMode); break; } else if (flags & Waited) { - DPRINTK("Waited\n"); writeb(ClearWaited, devpriv->mite->daq_io_addr + Group_1_First_Clear); async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; break; } else if (flags & PrimaryTC) { - DPRINTK("PrimaryTC\n"); writeb(ClearPrimaryTC, devpriv->mite->daq_io_addr + Group_1_First_Clear); async->events |= COMEDI_CB_EOA; } else if (flags & SecondaryTC) { - DPRINTK("SecondaryTC\n"); writeb(ClearSecondaryTC, devpriv->mite->daq_io_addr + Group_1_First_Clear); async->events |= COMEDI_CB_EOA; } -#if 0 - else { - printk("ni_pcidio: unknown interrupt\n"); - async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - writeb(0x00, - devpriv->mite->daq_io_addr + - Master_DMA_And_Interrupt_Control); - } -#endif + flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); status = readb(devpriv->mite->daq_io_addr + Interrupt_And_Window_Status); - /* DPRINTK("loop end: IntEn=0x%02x,flags=0x%02x," - "status=0x%02x\n", IntEn, flags, status); */ - /* ni_pcidio_print_flags(flags); */ - /* ni_pcidio_print_status(status); */ } out: - ni_pcidio_event(dev, s); + cfc_handle_events(dev, s); #if 0 if (!tag) { writeb(0x03, @@ -645,208 +495,98 @@ out: Master_DMA_And_Interrupt_Control); } #endif - return IRQ_HANDLED; -} - -#ifdef DEBUG_FLAGS -static const char *const flags_strings[] = { - "TransferReady", "CountExpired", "2", "3", - "4", "Waited", "PrimaryTC", "SecondaryTC", -}; - -static void ni_pcidio_print_flags(unsigned int flags) -{ - int i; - - printk(KERN_INFO "group_1_flags:"); - for (i = 7; i >= 0; i--) { - if (flags & (1 << i)) - printk(" %s", flags_strings[i]); - } - printk("\n"); -} - -static char *status_strings[] = { - "DataLeft1", "Reserved1", "Req1", "StopTrig1", - "DataLeft2", "Reserved2", "Req2", "StopTrig2", -}; - -static void ni_pcidio_print_status(unsigned int flags) -{ - int i; - - printk(KERN_INFO "group_status:"); - for (i = 7; i >= 0; i--) { - if (flags & (1 << i)) - printk(" %s", status_strings[i]); - } - printk("\n"); -} -#endif -#ifdef unused -static void debug_int(struct comedi_device *dev) -{ - int a, b; - static int n_int = 0; - struct timeval tv; - - do_gettimeofday(&tv); - a = readb(devpriv->mite->daq_io_addr + Group_Status); - b = readb(devpriv->mite->daq_io_addr + Group_1_Flags); - - if (n_int < 10) { - DPRINTK("status 0x%02x flags 0x%02x time %06d\n", a, b, - (int)tv.tv_usec); - } - - while (b & 1) { - writew(0xff, devpriv->mite->daq_io_addr + Group_1_FIFO); - b = readb(devpriv->mite->daq_io_addr + Group_1_Flags); - } - - b = readb(devpriv->mite->daq_io_addr + Group_1_Flags); - - if (n_int < 10) { - DPRINTK("new status 0x%02x\n", b); - n_int++; - } + spin_unlock(&dev->spinlock); + return IRQ_HANDLED; } -#endif static int ni_pcidio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 1) - return -EINVAL; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << CR_CHAN(insn->chanspec); - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << CR_CHAN(insn->chanspec)); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + struct nidio96_private *devpriv = dev->private; + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; + writel(s->io_bits, devpriv->mite->daq_io_addr + Port_Pin_Directions(0)); - return 1; + return insn->n; } static int ni_pcidio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + struct nidio96_private *devpriv = dev->private; + + if (comedi_dio_update_state(s, data)) writel(s->state, devpriv->mite->daq_io_addr + Port_IO(0)); - } + data[1] = readl(devpriv->mite->daq_io_addr + Port_IO(0)); - return 2; + return insn->n; } static int ni_pcidio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + unsigned int arg; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; + 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->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - /* same for both TRIG_INT and TRIG_NOW */ - cmd->start_arg = 0; - err++; - } #define MAX_SPEED (TIMER_BASE) /* in nanoseconds */ if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < MAX_SPEED) { - cmd->scan_begin_arg = MAX_SPEED; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + MAX_SPEED); /* no minimum speed */ } else { /* TRIG_EXT */ /* should be level/edge, hi/lo specification here */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; + if ((cmd->scan_begin_arg & ~(CR_EDGE | CR_INVERT)) != 0) { + cmd->scan_begin_arg &= (CR_EDGE | CR_INVERT); + err |= -EINVAL; } } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + 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_arg != 0) { - cmd->stop_arg = 0; - err++; - } + } else { /* TRIG_NONE */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -855,11 +595,9 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - ni_pcidio_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + ni_pcidio_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) @@ -893,6 +631,7 @@ static int ni_pcidio_ns_to_timer(int *nanosec, int round_mode) static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct nidio96_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; /* XXX configure ports for input */ @@ -941,7 +680,13 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) writeb(0, devpriv->mite->daq_io_addr + Sequence); writeb(0x00, devpriv->mite->daq_io_addr + ReqReg); writeb(4, devpriv->mite->daq_io_addr + BlockMode); - writeb(0, devpriv->mite->daq_io_addr + LinePolarities); + if (!(cmd->scan_begin_arg & CR_INVERT)) { + /* Leading Edge pulse mode */ + writeb(0, devpriv->mite->daq_io_addr + LinePolarities); + } else { + /* Trailing Edge pulse mode */ + writeb(2, devpriv->mite->daq_io_addr + LinePolarities); + } writeb(0x00, devpriv->mite->daq_io_addr + AckSer); writel(1, devpriv->mite->daq_io_addr + StartDelay); writeb(1, devpriv->mite->daq_io_addr + ReqDelay); @@ -998,30 +743,41 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) s->async->inttrig = ni_pcidio_inttrig; } - DPRINTK("ni_pcidio: command started\n"); return 0; } static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s) { + struct nidio96_private *devpriv = dev->private; int retval; + unsigned long flags; retval = ni_pcidio_request_di_mite_channel(dev); if (retval) return retval; - devpriv->di_mite_chan->dir = COMEDI_INPUT; + /* write alloc the entire buffer */ + comedi_buf_write_alloc(s, s->async->prealloc_bufsz); - mite_prep_dma(devpriv->di_mite_chan, 32, 32); + spin_lock_irqsave(&devpriv->mite_channel_lock, flags); + if (devpriv->di_mite_chan) { + mite_prep_dma(devpriv->di_mite_chan, 32, 32); + mite_dma_arm(devpriv->di_mite_chan); + } else + retval = -EIO; + spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); - mite_dma_arm(devpriv->di_mite_chan); - return 0; + return retval; } static int ni_pcidio_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != 0) + struct nidio96_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + if (trig_num != cmd->start_arg) return -EINVAL; writeb(devpriv->OpModeBits, devpriv->mite->daq_io_addr + OpMode); @@ -1033,6 +789,8 @@ static int ni_pcidio_inttrig(struct comedi_device *dev, static int ni_pcidio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct nidio96_private *devpriv = dev->private; + writeb(0x00, devpriv->mite->daq_io_addr + Master_DMA_And_Interrupt_Control); ni_pcidio_release_di_mite_channel(dev); @@ -1043,9 +801,10 @@ static int ni_pcidio_cancel(struct comedi_device *dev, static int ni_pcidio_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { + struct nidio96_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->di_mite_ring, s->async); + ret = mite_buf_change(devpriv->di_mite_ring, s); if (ret < 0) return ret; @@ -1054,11 +813,16 @@ static int ni_pcidio_change(struct comedi_device *dev, return 0; } -static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, - u8 *data, int data_len) +static int pci_6534_load_fpga(struct comedi_device *dev, + const u8 *data, size_t data_len, + unsigned long context) { + struct nidio96_private *devpriv = dev->private; static const int timeout = 1000; - int i, j; + int fpga_index = context; + int i; + size_t j; + writew(0x80 | fpga_index, devpriv->mite->daq_io_addr + Firmware_Control_Register); writew(0xc0 | fpga_index, @@ -1069,8 +833,9 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, udelay(1); } if (i == timeout) { - printk(KERN_WARNING "ni_pcidio: failed to load fpga %i, " - "waiting for status 0x2\n", fpga_index); + dev_warn(dev->class_dev, + "ni_pcidio: failed to load fpga %i, waiting for status 0x2\n", + fpga_index); return -EIO; } writew(0x80 | fpga_index, @@ -1081,8 +846,9 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, udelay(1); } if (i == timeout) { - printk(KERN_WARNING "ni_pcidio: failed to load fpga %i, " - "waiting for status 0x3\n", fpga_index); + dev_warn(dev->class_dev, + "ni_pcidio: failed to load fpga %i, waiting for status 0x3\n", + fpga_index); return -EIO; } for (j = 0; j + 1 < data_len;) { @@ -1097,8 +863,9 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, udelay(1); } if (i == timeout) { - printk("ni_pcidio: failed to load word into fpga %i\n", - fpga_index); + dev_warn(dev->class_dev, + "ni_pcidio: failed to load word into fpga %i\n", + fpga_index); return -EIO; } if (need_resched()) @@ -1110,13 +877,15 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, static int pci_6534_reset_fpga(struct comedi_device *dev, int fpga_index) { - return pci_6534_load_fpga(dev, fpga_index, NULL, 0); + return pci_6534_load_fpga(dev, NULL, 0, fpga_index); } static int pci_6534_reset_fpgas(struct comedi_device *dev) { + struct nidio96_private *devpriv = dev->private; int ret; int i; + writew(0x0, devpriv->mite->daq_io_addr + Firmware_Control_Register); for (i = 0; i < 3; ++i) { ret = pci_6534_reset_fpga(dev, i); @@ -1129,6 +898,8 @@ static int pci_6534_reset_fpgas(struct comedi_device *dev) static void pci_6534_init_main_fpga(struct comedi_device *dev) { + struct nidio96_private *devpriv = dev->private; + writel(0, devpriv->mite->daq_io_addr + FPGA_Control1_Register); writel(0, devpriv->mite->daq_io_addr + FPGA_Control2_Register); writel(0, devpriv->mite->daq_io_addr + FPGA_SCALS_Counter_Register); @@ -1137,223 +908,180 @@ static void pci_6534_init_main_fpga(struct comedi_device *dev) writel(0, devpriv->mite->daq_io_addr + FPGA_SCBMS_Counter_Register); } -static int pci_6534_upload_firmware(struct comedi_device *dev, int options[]) +static int pci_6534_upload_firmware(struct comedi_device *dev) { + struct nidio96_private *devpriv = dev->private; + static const char *const fw_file[3] = { + FW_PCI_6534_SCARAB_DI, /* loaded into scarab A for DI */ + FW_PCI_6534_SCARAB_DO, /* loaded into scarab B for DO */ + FW_PCI_6534_MAIN, /* loaded into main FPGA */ + }; int ret; - void *main_fpga_data, *scarab_a_data, *scarab_b_data; - int main_fpga_data_len, scarab_a_data_len, scarab_b_data_len; + int n; - if (options[COMEDI_DEVCONF_AUX_DATA_LENGTH] == 0) - return 0; ret = pci_6534_reset_fpgas(dev); if (ret < 0) return ret; - main_fpga_data = comedi_aux_data(options, 0); - main_fpga_data_len = options[COMEDI_DEVCONF_AUX_DATA0_LENGTH]; - ret = pci_6534_load_fpga(dev, 2, main_fpga_data, main_fpga_data_len); - if (ret < 0) - return ret; - pci_6534_init_main_fpga(dev); - scarab_a_data = comedi_aux_data(options, 1); - scarab_a_data_len = options[COMEDI_DEVCONF_AUX_DATA1_LENGTH]; - ret = pci_6534_load_fpga(dev, 0, scarab_a_data, scarab_a_data_len); - if (ret < 0) - return ret; - scarab_b_data = comedi_aux_data(options, 2); - scarab_b_data_len = options[COMEDI_DEVCONF_AUX_DATA2_LENGTH]; - ret = pci_6534_load_fpga(dev, 1, scarab_b_data, scarab_b_data_len); - if (ret < 0) - return ret; - return 0; + /* load main FPGA first, then the two scarabs */ + for (n = 2; n >= 0; n--) { + ret = comedi_load_firmware(dev, &devpriv->mite->pcidev->dev, + fw_file[n], + pci_6534_load_fpga, n); + if (ret == 0 && n == 2) + pci_6534_init_main_fpga(dev); + if (ret < 0) + break; + } + return ret; +} + +static void nidio_reset_board(struct comedi_device *dev) +{ + struct nidio96_private *devpriv = dev->private; + void __iomem *daq_mmio = devpriv->mite->daq_io_addr; + + writel(0, daq_mmio + Port_IO(0)); + writel(0, daq_mmio + Port_Pin_Directions(0)); + writel(0, daq_mmio + Port_Pin_Mask(0)); + + /* disable interrupts on board */ + writeb(0, daq_mmio + Master_DMA_And_Interrupt_Control); } -static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int nidio_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct nidio_board *board = NULL; + struct nidio96_private *devpriv; struct comedi_subdevice *s; - int i; int ret; - int n_subdevices; unsigned int irq; - printk(KERN_INFO "comedi%d: nidio:", dev->minor); + if (context < ARRAY_SIZE(nidio_boards)) + board = &nidio_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; - ret = alloc_private(dev, sizeof(struct nidio96_private)); - if (ret < 0) + ret = comedi_pci_enable(dev); + if (ret) return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + spin_lock_init(&devpriv->mite_channel_lock); - ret = nidio_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; ret = mite_setup(devpriv->mite); if (ret < 0) { - printk(KERN_WARNING "error setting up mite\n"); + dev_warn(dev->class_dev, "error setting up mite\n"); return ret; } - comedi_set_hw_dev(dev, &devpriv->mite->pcidev->dev); + devpriv->di_mite_ring = mite_alloc_ring(devpriv->mite); if (devpriv->di_mite_ring == NULL) return -ENOMEM; - dev->board_name = this_board->name; - irq = mite_irq(devpriv->mite); - printk(KERN_INFO " %s", dev->board_name); - if (this_board->uses_firmware) { - ret = pci_6534_upload_firmware(dev, it->options); + if (board->uses_firmware) { + ret = pci_6534_upload_firmware(dev); if (ret < 0) return ret; } - if (!this_board->is_diodaq) - n_subdevices = this_board->n_8255; - else - n_subdevices = 1; - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) + nidio_reset_board(dev); + + ret = comedi_alloc_subdevices(dev, 1); + if (ret) return ret; - if (!this_board->is_diodaq) { - for (i = 0; i < this_board->n_8255; i++) { - subdev_8255_init(dev, dev->subdevices + i, - nidio96_8255_cb, - (unsigned long)(devpriv->mite-> - daq_io_addr + - NIDIO_8255_BASE(i))); - } - } else { - - printk(KERN_INFO " rev=%d", - readb(devpriv->mite->daq_io_addr + Chip_Version)); - - s = dev->subdevices + 0; - - dev->read_subdev = s; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_PACKED | - SDF_CMD_READ; - s->n_chan = 32; - s->range_table = &range_digital; - s->maxdata = 1; - s->insn_config = &ni_pcidio_insn_config; - s->insn_bits = &ni_pcidio_insn_bits; - s->do_cmd = &ni_pcidio_cmd; - s->do_cmdtest = &ni_pcidio_cmdtest; - s->cancel = &ni_pcidio_cancel; - s->len_chanlist = 32; /* XXX */ - s->buf_change = &ni_pcidio_change; - s->async_dma_dir = DMA_BIDIRECTIONAL; - - writel(0, devpriv->mite->daq_io_addr + Port_IO(0)); - writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0)); - writel(0, devpriv->mite->daq_io_addr + Port_Pin_Mask(0)); - - /* disable interrupts on board */ - writeb(0x00, - devpriv->mite->daq_io_addr + - Master_DMA_And_Interrupt_Control); + dev_info(dev->class_dev, "%s rev=%d\n", dev->board_name, + readb(devpriv->mite->daq_io_addr + Chip_Version)); + + s = &dev->subdevices[0]; + + dev->read_subdev = s; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = + SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_PACKED | + SDF_CMD_READ; + s->n_chan = 32; + s->range_table = &range_digital; + s->maxdata = 1; + s->insn_config = &ni_pcidio_insn_config; + s->insn_bits = &ni_pcidio_insn_bits; + s->do_cmd = &ni_pcidio_cmd; + s->do_cmdtest = &ni_pcidio_cmdtest; + s->cancel = &ni_pcidio_cancel; + s->len_chanlist = 32; /* XXX */ + s->buf_change = &ni_pcidio_change; + s->async_dma_dir = DMA_BIDIRECTIONAL; + s->poll = &ni_pcidio_poll; + irq = mite_irq(devpriv->mite); + if (irq) { ret = request_irq(irq, nidio_interrupt, IRQF_SHARED, - "ni_pcidio", dev); - if (ret < 0) - printk(KERN_WARNING " irq not available"); - - dev->irq = irq; + dev->board_name, dev); + if (ret == 0) + dev->irq = irq; } - printk("\n"); - return 0; } -static int nidio_detach(struct comedi_device *dev) +static void nidio_detach(struct comedi_device *dev) { - int i; - - if (this_board && !this_board->is_diodaq) { - for (i = 0; i < this_board->n_8255; i++) - subdev_8255_cleanup(dev, dev->subdevices + i); - } + struct nidio96_private *devpriv = dev->private; if (dev->irq) free_irq(dev->irq, dev); - if (devpriv) { if (devpriv->di_mite_ring) { mite_free_ring(devpriv->di_mite_ring); devpriv->di_mite_ring = NULL; } - if (devpriv->mite) + if (devpriv->mite) { mite_unsetup(devpriv->mite); - } - return 0; -} - -static int nidio_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < n_nidio_boards; i++) { - if (mite_device_id(mite) == nidio_boards[i].dev_id) { - dev->board_ptr = nidio_boards + i; - devpriv->mite = mite; - - return 0; - } + mite_free(devpriv->mite); } } - printk(KERN_WARNING "no device found\n"); - mite_list_devices(); - return -EIO; -} - -static int __devinit driver_pcidio_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_pcidio.driver_name); + comedi_pci_disable(dev); } -static void __devexit driver_pcidio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_pcidio_pci_driver = { - .id_table = ni_pcidio_pci_table, - .probe = &driver_pcidio_pci_probe, - .remove = __devexit_p(&driver_pcidio_pci_remove) +static struct comedi_driver ni_pcidio_driver = { + .driver_name = "ni_pcidio", + .module = THIS_MODULE, + .auto_attach = nidio_auto_attach, + .detach = nidio_detach, }; -static int __init driver_pcidio_init_module(void) +static int ni_pcidio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - int retval; - - retval = comedi_driver_register(&driver_pcidio); - if (retval < 0) - return retval; - - driver_pcidio_pci_driver.name = (char *)driver_pcidio.driver_name; - return pci_register_driver(&driver_pcidio_pci_driver); + return comedi_pci_auto_config(dev, &ni_pcidio_driver, id->driver_data); } -static void __exit driver_pcidio_cleanup_module(void) -{ - pci_unregister_driver(&driver_pcidio_pci_driver); - comedi_driver_unregister(&driver_pcidio); -} +static const struct pci_device_id ni_pcidio_pci_table[] = { + { PCI_VDEVICE(NI, 0x1150), BOARD_PCIDIO_32HS }, + { PCI_VDEVICE(NI, 0x12b0), BOARD_PCI6534 }, + { PCI_VDEVICE(NI, 0x1320), BOARD_PXI6533 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table); -module_init(driver_pcidio_init_module); -module_exit(driver_pcidio_cleanup_module); +static struct pci_driver ni_pcidio_pci_driver = { + .name = "ni_pcidio", + .id_table = ni_pcidio_pci_table, + .probe = ni_pcidio_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(ni_pcidio_driver, ni_pcidio_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 9148abdad07..89300dc78e3 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -14,10 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Driver: ni_pcimio @@ -29,14 +25,15 @@ Devices: [National Instruments] PCI-MIO-16XE-50 (ni_pcimio), PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, PCI-MIO-16E-4, PCI-6014, PCI-6040E, PXI-6040E, PCI-6030E, PCI-6031E, PCI-6032E, PCI-6033E, PCI-6071E, PCI-6023E, PCI-6024E, PCI-6025E, PXI-6025E, PCI-6034E, PCI-6035E, PCI-6052E, - PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224, PCI-6225, PXI-6225, - PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PCI-6254, PCI-6259, PCIe-6259, + PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224, + PCI-6225, PXI-6225, PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PXIe-6251, + PCI-6254, PCI-6259, PCIe-6259, PCI-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289, PCI-6711, PXI-6711, PCI-6713, PXI-6713, PXI-6071E, PCI-6070E, PXI-6070E, PXI-6052E, PCI-6036E, PCI-6731, PCI-6733, PXI-6733, PCI-6143, PXI-6143 -Updated: Wed, 03 Dec 2008 10:51:47 +0000 +Updated: Mon, 09 Jan 2012 14:52:48 +0000 These boards are almost identical to the AT-MIO E series, except that they use the PCI bus instead of ISA (i.e., AT). See the notes for @@ -109,16 +106,16 @@ Bugs: */ +#include <linux/module.h> +#include <linux/delay.h> + #include "../comedidev.h" #include <asm/byteorder.h> -#include <linux/delay.h> #include "ni_stc.h" #include "mite.h" -/* #define PCI_DEBUG */ - #define PCIDMA #define PCIMIO 1 @@ -128,65 +125,6 @@ Bugs: #define DRV_NAME "ni_pcimio" -/* The following two tables must be in the same order */ -static DEFINE_PCI_DEVICE_TABLE(ni_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0162)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1170)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1180)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1190)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x11d0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1270)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1330)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1340)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1350)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14e0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x14f0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1580)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x15b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1880)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1870)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x18c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2410)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2420)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2430)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2890)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x28c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a60)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a70)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2a80)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ab0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b80)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2b90)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2c80)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x2ca0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70aa)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ab)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70ac)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70af)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b4)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b6)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b7)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70b8)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bc)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bd)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70bf)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70c0)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x70f2)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x710d)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716c)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x716d)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)}, - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, ni_pci_table); - /* These are not all the possible ao ranges for 628x boards. They can do OFFSET +- REFERENCE where OFFSET can be 0V, 5V, APFI<0,1>, or AO<0...3> and RANGE can @@ -194,1092 +132,920 @@ MODULE_DEVICE_TABLE(pci, ni_pci_table); 63 different possibilities. An AO channel can not act as it's own OFFSET or REFERENCE. */ -static const struct comedi_lrange range_ni_M_628x_ao = { 8, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2, 2), - RANGE(-1, 1), - RANGE(-5, 15), - RANGE(0, 10), - RANGE(3, 7), - RANGE(4, 6), - RANGE_ext(-1, 1) - } +static const struct comedi_lrange range_ni_M_628x_ao = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2), + BIP_RANGE(1), + RANGE(-5, 15), + UNI_RANGE(10), + RANGE(3, 7), + RANGE(4, 6), + RANGE_ext(-1, 1) + } }; -static const struct comedi_lrange range_ni_M_625x_ao = { 3, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE_ext(-1, 1) - } +static const struct comedi_lrange range_ni_M_625x_ao = { + 3, { + BIP_RANGE(10), + BIP_RANGE(5), + RANGE_ext(-1, 1) + } }; -static const struct comedi_lrange range_ni_M_622x_ao = { 1, { - RANGE(-10, 10), - } +enum ni_pcimio_boardid { + BOARD_PCIMIO_16XE_50, + BOARD_PCIMIO_16XE_10, + BOARD_PCI6014, + BOARD_PXI6030E, + BOARD_PCIMIO_16E_1, + BOARD_PCIMIO_16E_4, + BOARD_PXI6040E, + BOARD_PCI6031E, + BOARD_PCI6032E, + BOARD_PCI6033E, + BOARD_PCI6071E, + BOARD_PCI6023E, + BOARD_PCI6024E, + BOARD_PCI6025E, + BOARD_PXI6025E, + BOARD_PCI6034E, + BOARD_PCI6035E, + BOARD_PCI6052E, + BOARD_PCI6110, + BOARD_PCI6111, + /* BOARD_PCI6115, */ + /* BOARD_PXI6115, */ + BOARD_PCI6711, + BOARD_PXI6711, + BOARD_PCI6713, + BOARD_PXI6713, + BOARD_PCI6731, + /* BOARD_PXI6731, */ + BOARD_PCI6733, + BOARD_PXI6733, + BOARD_PXI6071E, + BOARD_PXI6070E, + BOARD_PXI6052E, + BOARD_PXI6031E, + BOARD_PCI6036E, + BOARD_PCI6220, + BOARD_PCI6221, + BOARD_PCI6221_37PIN, + BOARD_PCI6224, + BOARD_PXI6224, + BOARD_PCI6225, + BOARD_PXI6225, + BOARD_PCI6229, + BOARD_PCI6250, + BOARD_PCI6251, + BOARD_PCIE6251, + BOARD_PXIE6251, + BOARD_PCI6254, + BOARD_PCI6259, + BOARD_PCIE6259, + BOARD_PCI6280, + BOARD_PCI6281, + BOARD_PXI6281, + BOARD_PCI6284, + BOARD_PCI6289, + BOARD_PCI6143, + BOARD_PXI6143, }; static const struct ni_board_struct ni_boards[] = { - { - .device_id = 0x0162, /* NI also says 0x1620. typo? */ - .name = "pci-mio-16xe-50", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 2048, - .alwaysdither = 1, - .gainlkup = ai_gain_8, - .ai_speed = 50000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 50000, - .num_p0_dio_channels = 8, - .caldac = {dac8800, dac8043}, - .has_8255 = 0, - }, - { - .device_id = 0x1170, - .name = "pci-mio-16xe-10", /* aka pci-6030E */ - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_14, - .ai_speed = 10000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 10000, - .num_p0_dio_channels = 8, - .caldac = {dac8800, dac8043, ad8522}, - .has_8255 = 0, - }, - { - .device_id = 0x28c0, - .name = "pci-6014", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 100000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, - .has_8255 = 0, - }, - { - .device_id = 0x11d0, - .name = "pxi-6030e", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_14, - .ai_speed = 10000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 10000, - .num_p0_dio_channels = 8, - .caldac = {dac8800, dac8043, ad8522}, - .has_8255 = 0, - }, - { - .device_id = 0x1180, - .name = "pci-mio-16e-1", /* aka pci-6070e */ - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 0, - .gainlkup = ai_gain_16, - .ai_speed = 800, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .caldac = {mb88341}, - .has_8255 = 0, - }, - { - .device_id = 0x1190, - .name = "pci-mio-16e-4", /* aka pci-6040e */ - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 0, - .gainlkup = ai_gain_16, - /* .Note = there have been reported problems with full speed - * on this board */ - .ai_speed = 2000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 512, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, /* doc says mb88341 */ - .has_8255 = 0, - }, - { - .device_id = 0x11c0, - .name = "pxi-6040e", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 0, - .gainlkup = ai_gain_16, - .ai_speed = 2000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 512, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .caldac = {mb88341}, - .has_8255 = 0, - }, - - { - .device_id = 0x1330, - .name = "pci-6031e", - .n_adchan = 64, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_14, - .ai_speed = 10000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 10000, - .num_p0_dio_channels = 8, - .caldac = {dac8800, dac8043, ad8522}, - .has_8255 = 0, - }, - { - .device_id = 0x1270, - .name = "pci-6032e", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_14, - .ai_speed = 10000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .caldac = {dac8800, dac8043, ad8522}, - .has_8255 = 0, - }, - { - .device_id = 0x1340, - .name = "pci-6033e", - .n_adchan = 64, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_14, - .ai_speed = 10000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .caldac = {dac8800, dac8043, ad8522}, - .has_8255 = 0, - }, - { - .device_id = 0x1350, - .name = "pci-6071e", - .n_adchan = 64, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_16, - .ai_speed = 800, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, - .has_8255 = 0, - }, - { - .device_id = 0x2a60, - .name = "pci-6023e", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 0, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 0, - .aobits = 0, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, /* manual is wrong */ - .has_8255 = 0, - }, - { - .device_id = 0x2a70, - .name = "pci-6024e", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 0, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 100000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, /* manual is wrong */ - .has_8255 = 0, - }, - { - .device_id = 0x2a80, - .name = "pci-6025e", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 0, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 100000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, /* manual is wrong */ - .has_8255 = 1, - }, - { - .device_id = 0x2ab0, - .name = "pxi-6025e", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 0, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 0, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 100000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, /* manual is wrong */ - .has_8255 = 1, - }, - - { - .device_id = 0x2ca0, - .name = "pci-6034e", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, - .has_8255 = 0, - }, - { - .device_id = 0x2c80, - .name = "pci-6035e", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 100000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, - .has_8255 = 0, - }, - { - .device_id = 0x18b0, - .name = "pci-6052e", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_16, - .ai_speed = 3000, - .n_aochan = 2, - .aobits = 16, - .ao_unipolar = 1, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_speed = 3000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug, ad8804_debug, ad8522}, /* manual is wrong */ - }, - {.device_id = 0x14e0, - .name = "pci-6110", - .n_adchan = 4, - .adbits = 12, - .ai_fifo_depth = 8192, - .alwaysdither = 0, - .gainlkup = ai_gain_611x, - .ai_speed = 200, - .n_aochan = 2, - .aobits = 16, - .reg_type = ni_reg_611x, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_fifo_depth = 2048, - .ao_speed = 250, - .num_p0_dio_channels = 8, - .caldac = {ad8804, ad8804}, - }, - { - .device_id = 0x14f0, - .name = "pci-6111", - .n_adchan = 2, - .adbits = 12, - .ai_fifo_depth = 8192, - .alwaysdither = 0, - .gainlkup = ai_gain_611x, - .ai_speed = 200, - .n_aochan = 2, - .aobits = 16, - .reg_type = ni_reg_611x, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_fifo_depth = 2048, - .ao_speed = 250, - .num_p0_dio_channels = 8, - .caldac = {ad8804, ad8804}, - }, + [BOARD_PCIMIO_16XE_50] = { + .name = "pci-mio-16xe-50", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 2048, + .alwaysdither = 1, + .gainlkup = ai_gain_8, + .ai_speed = 50000, + .n_aochan = 2, + .aobits = 12, + .ao_range_table = &range_bipolar10, + .ao_speed = 50000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043 }, + }, + [BOARD_PCIMIO_16XE_10] = { + .name = "pci-mio-16xe-10", /* aka pci-6030E */ + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_14, + .ai_speed = 10000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 10000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043, ad8522 }, + }, + [BOARD_PCI6014] = { + .name = "pci-6014", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 16, + .ao_range_table = &range_bipolar10, + .ao_speed = 100000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, + [BOARD_PXI6030E] = { + .name = "pxi-6030e", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_14, + .ai_speed = 10000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 10000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043, ad8522 }, + }, + [BOARD_PCIMIO_16E_1] = { + .name = "pci-mio-16e-1", /* aka pci-6070e */ + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .gainlkup = ai_gain_16, + .ai_speed = 800, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .caldac = { mb88341 }, + }, + [BOARD_PCIMIO_16E_4] = { + .name = "pci-mio-16e-4", /* aka pci-6040e */ + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .gainlkup = ai_gain_16, + /* + * there have been reported problems with + * full speed on this board + */ + .ai_speed = 2000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 512, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, /* doc says mb88341 */ + }, + [BOARD_PXI6040E] = { + .name = "pxi-6040e", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .gainlkup = ai_gain_16, + .ai_speed = 2000, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 512, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .caldac = { mb88341 }, + }, + [BOARD_PCI6031E] = { + .name = "pci-6031e", + .n_adchan = 64, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_14, + .ai_speed = 10000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 10000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043, ad8522 }, + }, + [BOARD_PCI6032E] = { + .name = "pci-6032e", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_14, + .ai_speed = 10000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043, ad8522 }, + }, + [BOARD_PCI6033E] = { + .name = "pci-6033e", + .n_adchan = 64, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_14, + .ai_speed = 10000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043, ad8522 }, + }, + [BOARD_PCI6071E] = { + .name = "pci-6071e", + .n_adchan = 64, + .adbits = 12, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_16, + .ai_speed = 800, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, + [BOARD_PCI6023E] = { + .name = "pci-6023e", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, /* manual is wrong */ + }, + [BOARD_PCI6024E] = { + .name = "pci-6024e", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 12, + .ao_range_table = &range_bipolar10, + .ao_speed = 100000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, /* manual is wrong */ + }, + [BOARD_PCI6025E] = { + .name = "pci-6025e", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 12, + .ao_range_table = &range_bipolar10, + .ao_speed = 100000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, /* manual is wrong */ + .has_8255 = 1, + }, + [BOARD_PXI6025E] = { + .name = "pxi-6025e", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 12, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 100000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, /* manual is wrong */ + .has_8255 = 1, + }, + [BOARD_PCI6034E] = { + .name = "pci-6034e", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, + [BOARD_PCI6035E] = { + .name = "pci-6035e", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 12, + .ao_range_table = &range_bipolar10, + .ao_speed = 100000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, + [BOARD_PCI6052E] = { + .name = "pci-6052e", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_16, + .ai_speed = 3000, + .n_aochan = 2, + .aobits = 16, + .ao_unipolar = 1, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_speed = 3000, + .num_p0_dio_channels = 8, + /* manual is wrong */ + .caldac = { ad8804_debug, ad8804_debug, ad8522 }, + }, + [BOARD_PCI6110] = { + .name = "pci-6110", + .n_adchan = 4, + .adbits = 12, + .ai_fifo_depth = 8192, + .alwaysdither = 0, + .gainlkup = ai_gain_611x, + .ai_speed = 200, + .n_aochan = 2, + .aobits = 16, + .reg_type = ni_reg_611x, + .ao_range_table = &range_bipolar10, + .ao_fifo_depth = 2048, + .ao_speed = 250, + .num_p0_dio_channels = 8, + .caldac = { ad8804, ad8804 }, + }, + [BOARD_PCI6111] = { + .name = "pci-6111", + .n_adchan = 2, + .adbits = 12, + .ai_fifo_depth = 8192, + .gainlkup = ai_gain_611x, + .ai_speed = 200, + .n_aochan = 2, + .aobits = 16, + .reg_type = ni_reg_611x, + .ao_range_table = &range_bipolar10, + .ao_fifo_depth = 2048, + .ao_speed = 250, + .num_p0_dio_channels = 8, + .caldac = { ad8804, ad8804 }, + }, #if 0 /* The 6115 boards probably need their own driver */ - { - .device_id = 0x2ed0, - .name = "pci-6115", - .n_adchan = 4, - .adbits = 12, - .ai_fifo_depth = 8192, - .alwaysdither = 0, - .gainlkup = ai_gain_611x, - .ai_speed = 100, - .n_aochan = 2, - .aobits = 16, - .ao_671x = 1, - .ao_unipolar = 0, - .ao_fifo_depth = 2048, - .ao_speed = 250, - .num_p0_dio_channels = 8, - .reg_611x = 1, - .caldac = {ad8804_debug, ad8804_debug, ad8804_debug}, /* XXX */ - }, + [BOARD_PCI6115] = { /* .device_id = 0x2ed0, */ + .name = "pci-6115", + .n_adchan = 4, + .adbits = 12, + .ai_fifo_depth = 8192, + .gainlkup = ai_gain_611x, + .ai_speed = 100, + .n_aochan = 2, + .aobits = 16, + .ao_671x = 1, + .ao_fifo_depth = 2048, + .ao_speed = 250, + .num_p0_dio_channels = 8, + .reg_611x = 1, + /* XXX */ + .caldac = { ad8804_debug, ad8804_debug, ad8804_debug }, + }, #endif #if 0 - { - .device_id = 0x0000, - .name = "pxi-6115", - .n_adchan = 4, - .adbits = 12, - .ai_fifo_depth = 8192, - .alwaysdither = 0, - .gainlkup = ai_gain_611x, - .ai_speed = 100, - .n_aochan = 2, - .aobits = 16, - .ao_671x = 1, - .ao_unipolar = 0, - .ao_fifo_depth = 2048, - .ao_speed = 250, - .reg_611x = 1, - .num_p0_dio_channels = 8, - caldac = {ad8804_debug, ad8804_debug, ad8804_debug}, /* XXX */ - }, + [BOARD_PXI6115] = { /* .device_id = ????, */ + .name = "pxi-6115", + .n_adchan = 4, + .adbits = 12, + .ai_fifo_depth = 8192, + .gainlkup = ai_gain_611x, + .ai_speed = 100, + .n_aochan = 2, + .aobits = 16, + .ao_671x = 1, + .ao_fifo_depth = 2048, + .ao_speed = 250, + .reg_611x = 1, + .num_p0_dio_channels = 8, + /* XXX */ + .caldac = { ad8804_debug, ad8804_debug, ad8804_debug }, + }, #endif - { - .device_id = 0x1880, - .name = "pci-6711", - .n_adchan = 0, /* no analog input */ - .n_aochan = 4, - .aobits = 12, - .ao_unipolar = 0, - .ao_fifo_depth = 16384, - /* data sheet says 8192, but fifo really holds 16384 samples */ - .ao_range_table = &range_bipolar10, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_6711, - .caldac = {ad8804_debug}, - }, - { - .device_id = 0x2b90, - .name = "pxi-6711", - .n_adchan = 0, /* no analog input */ - .n_aochan = 4, - .aobits = 12, - .ao_unipolar = 0, - .ao_fifo_depth = 16384, - .ao_range_table = &range_bipolar10, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_6711, - .caldac = {ad8804_debug}, - }, - { - .device_id = 0x1870, - .name = "pci-6713", - .n_adchan = 0, /* no analog input */ - .n_aochan = 8, - .aobits = 12, - .ao_unipolar = 0, - .ao_fifo_depth = 16384, - .ao_range_table = &range_bipolar10, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_6713, - .caldac = {ad8804_debug, ad8804_debug}, - }, - { - .device_id = 0x2b80, - .name = "pxi-6713", - .n_adchan = 0, /* no analog input */ - .n_aochan = 8, - .aobits = 12, - .ao_unipolar = 0, - .ao_fifo_depth = 16384, - .ao_range_table = &range_bipolar10, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_6713, - .caldac = {ad8804_debug, ad8804_debug}, - }, - { - .device_id = 0x2430, - .name = "pci-6731", - .n_adchan = 0, /* no analog input */ - .n_aochan = 4, - .aobits = 16, - .ao_unipolar = 0, - .ao_fifo_depth = 8192, - .ao_range_table = &range_bipolar10, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_6711, - .caldac = {ad8804_debug}, - }, -#if 0 /* need device ids */ - { - .device_id = 0x0, - .name = "pxi-6731", - .n_adchan = 0, /* no analog input */ - .n_aochan = 4, - .aobits = 16, - .ao_unipolar = 0, - .ao_fifo_depth = 8192, - .ao_range_table = &range_bipolar10, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_6711, - .caldac = {ad8804_debug}, - }, + [BOARD_PCI6711] = { + .name = "pci-6711", + .n_aochan = 4, + .aobits = 12, + /* data sheet says 8192, but fifo really holds 16384 samples */ + .ao_fifo_depth = 16384, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_6711, + .caldac = { ad8804_debug }, + }, + [BOARD_PXI6711] = { + .name = "pxi-6711", + .n_aochan = 4, + .aobits = 12, + .ao_fifo_depth = 16384, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_6711, + .caldac = { ad8804_debug }, + }, + [BOARD_PCI6713] = { + .name = "pci-6713", + .n_aochan = 8, + .aobits = 12, + .ao_fifo_depth = 16384, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_6713, + .caldac = { ad8804_debug, ad8804_debug }, + }, + [BOARD_PXI6713] = { + .name = "pxi-6713", + .n_aochan = 8, + .aobits = 12, + .ao_fifo_depth = 16384, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_6713, + .caldac = { ad8804_debug, ad8804_debug }, + }, + [BOARD_PCI6731] = { + .name = "pci-6731", + .n_aochan = 4, + .aobits = 16, + .ao_fifo_depth = 8192, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_6711, + .caldac = { ad8804_debug }, + }, +#if 0 + [BOARD_PXI6731] = { /* .device_id = ????, */ + .name = "pxi-6731", + .n_aochan = 4, + .aobits = 16, + .ao_fifo_depth = 8192, + .ao_range_table = &range_bipolar10, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_6711, + .caldac = { ad8804_debug }, + }, #endif - { - .device_id = 0x2410, - .name = "pci-6733", - .n_adchan = 0, /* no analog input */ - .n_aochan = 8, - .aobits = 16, - .ao_unipolar = 0, - .ao_fifo_depth = 16384, - .ao_range_table = &range_bipolar10, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_6713, - .caldac = {ad8804_debug, ad8804_debug}, - }, - { - .device_id = 0x2420, - .name = "pxi-6733", - .n_adchan = 0, /* no analog input */ - .n_aochan = 8, - .aobits = 16, - .ao_unipolar = 0, - .ao_fifo_depth = 16384, - .ao_range_table = &range_bipolar10, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_6713, - .caldac = {ad8804_debug, ad8804_debug}, - }, - { - .device_id = 0x15b0, - .name = "pxi-6071e", - .n_adchan = 64, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_16, - .ai_speed = 800, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, - .has_8255 = 0, - }, - { - .device_id = 0x11b0, - .name = "pxi-6070e", - .n_adchan = 16, - .adbits = 12, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_16, - .ai_speed = 800, - .n_aochan = 2, - .aobits = 12, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 1000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, - .has_8255 = 0, - }, - { - .device_id = 0x18c0, - .name = "pxi-6052e", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_16, - .ai_speed = 3000, - .n_aochan = 2, - .aobits = 16, - .ao_unipolar = 1, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_speed = 3000, - .num_p0_dio_channels = 8, - .caldac = {mb88341, mb88341, ad8522}, - }, - { - .device_id = 0x1580, - .name = "pxi-6031e", - .n_adchan = 64, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_14, - .ai_speed = 10000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 2048, - .ao_range_table = &range_ni_E_ao_ext, - .ao_unipolar = 1, - .ao_speed = 10000, - .num_p0_dio_channels = 8, - .caldac = {dac8800, dac8043, ad8522}, - }, - { - .device_id = 0x2890, - .name = "pci-6036e", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - .alwaysdither = 1, - .gainlkup = ai_gain_4, - .ai_speed = 5000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 0, - .ao_range_table = &range_bipolar10, - .ao_unipolar = 0, - .ao_speed = 100000, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug}, - .has_8255 = 0, - }, - { - .device_id = 0x70b0, - .name = "pci-6220", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 512, - /* .FIXME = guess */ - .gainlkup = ai_gain_622x, - .ai_speed = 4000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .num_p0_dio_channels = 8, - .reg_type = ni_reg_622x, - .ao_unipolar = 0, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70af, - .name = "pci-6221", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_622x, - .ai_speed = 4000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_622x_ao, - .reg_type = ni_reg_622x, - .ao_unipolar = 0, - .ao_speed = 1200, - .num_p0_dio_channels = 8, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x71bc, - .name = "pci-6221_37pin", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_622x, - .ai_speed = 4000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_622x_ao, - .reg_type = ni_reg_622x, - .ao_unipolar = 0, - .ao_speed = 1200, - .num_p0_dio_channels = 8, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70f2, - .name = "pci-6224", - .n_adchan = 32, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_622x, - .ai_speed = 4000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .reg_type = ni_reg_622x, - .ao_unipolar = 0, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70f3, - .name = "pxi-6224", - .n_adchan = 32, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_622x, - .ai_speed = 4000, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .reg_type = ni_reg_622x, - .ao_unipolar = 0, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x716c, - .name = "pci-6225", - .n_adchan = 80, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_622x, - .ai_speed = 4000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_622x_ao, - .reg_type = ni_reg_622x, - .ao_unipolar = 0, - .ao_speed = 1200, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x716d, - .name = "pxi-6225", - .n_adchan = 80, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_622x, - .ai_speed = 4000, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_622x_ao, - .reg_type = ni_reg_622x, - .ao_unipolar = 0, - .ao_speed = 1200, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, + [BOARD_PCI6733] = { + .name = "pci-6733", + .n_aochan = 8, + .aobits = 16, + .ao_fifo_depth = 16384, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_6713, + .caldac = { ad8804_debug, ad8804_debug }, + }, + [BOARD_PXI6733] = { + .name = "pxi-6733", + .n_aochan = 8, + .aobits = 16, + .ao_fifo_depth = 16384, + .ao_range_table = &range_bipolar10, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_6713, + .caldac = { ad8804_debug, ad8804_debug }, + }, + [BOARD_PXI6071E] = { + .name = "pxi-6071e", + .n_adchan = 64, + .adbits = 12, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_16, + .ai_speed = 800, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, + [BOARD_PXI6070E] = { + .name = "pxi-6070e", + .n_adchan = 16, + .adbits = 12, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_16, + .ai_speed = 800, + .n_aochan = 2, + .aobits = 12, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 1000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, + [BOARD_PXI6052E] = { + .name = "pxi-6052e", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_16, + .ai_speed = 3000, + .n_aochan = 2, + .aobits = 16, + .ao_unipolar = 1, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_speed = 3000, + .num_p0_dio_channels = 8, + .caldac = { mb88341, mb88341, ad8522 }, + }, + [BOARD_PXI6031E] = { + .name = "pxi-6031e", + .n_adchan = 64, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_14, + .ai_speed = 10000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 2048, + .ao_range_table = &range_ni_E_ao_ext, + .ao_unipolar = 1, + .ao_speed = 10000, + .num_p0_dio_channels = 8, + .caldac = { dac8800, dac8043, ad8522 }, + }, + [BOARD_PCI6036E] = { + .name = "pci-6036e", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, + .alwaysdither = 1, + .gainlkup = ai_gain_4, + .ai_speed = 5000, + .n_aochan = 2, + .aobits = 16, + .ao_range_table = &range_bipolar10, + .ao_speed = 100000, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug }, + }, + [BOARD_PCI6220] = { + .name = "pci-6220", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 512, /* FIXME: guess */ + .gainlkup = ai_gain_622x, + .ai_speed = 4000, + .num_p0_dio_channels = 8, + .reg_type = ni_reg_622x, + .caldac = { caldac_none }, + }, + [BOARD_PCI6221] = { + .name = "pci-6221", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_622x, + .ai_speed = 4000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_bipolar10, + .reg_type = ni_reg_622x, + .ao_speed = 1200, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PCI6221_37PIN] = { + .name = "pci-6221_37pin", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_622x, + .ai_speed = 4000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_bipolar10, + .reg_type = ni_reg_622x, + .ao_speed = 1200, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PCI6224] = { + .name = "pci-6224", + .n_adchan = 32, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_622x, + .ai_speed = 4000, + .reg_type = ni_reg_622x, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PXI6224] = { + .name = "pxi-6224", + .n_adchan = 32, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_622x, + .ai_speed = 4000, + .reg_type = ni_reg_622x, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PCI6225] = { + .name = "pci-6225", + .n_adchan = 80, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_622x, + .ai_speed = 4000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_bipolar10, + .reg_type = ni_reg_622x, + .ao_speed = 1200, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PXI6225] = { + .name = "pxi-6225", + .n_adchan = 80, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_622x, + .ai_speed = 4000, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_bipolar10, + .reg_type = ni_reg_622x, + .ao_speed = 1200, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PCI6229] = { + .name = "pci-6229", + .n_adchan = 32, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_622x, + .ai_speed = 4000, + .n_aochan = 4, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_bipolar10, + .reg_type = ni_reg_622x, + .ao_speed = 1200, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PCI6250] = { + .name = "pci-6250", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_628x, + .ai_speed = 800, + .reg_type = ni_reg_625x, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PCI6251] = { + .name = "pci-6251", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_628x, + .ai_speed = 800, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PCIE6251] = { + .name = "pcie-6251", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_628x, + .ai_speed = 800, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PXIE6251] = { + .name = "pxie-6251", + .n_adchan = 16, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_628x, + .ai_speed = 800, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PCI6254] = { + .name = "pci-6254", + .n_adchan = 32, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_628x, + .ai_speed = 800, + .reg_type = ni_reg_625x, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PCI6259] = { + .name = "pci-6259", + .n_adchan = 32, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_628x, + .ai_speed = 800, + .n_aochan = 4, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_speed = 350, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PCIE6259] = { + .name = "pcie-6259", + .n_adchan = 32, + .adbits = 16, + .ai_fifo_depth = 4095, + .gainlkup = ai_gain_628x, + .ai_speed = 800, + .n_aochan = 4, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_ni_M_625x_ao, + .reg_type = ni_reg_625x, + .ao_speed = 350, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PCI6280] = { + .name = "pci-6280", + .n_adchan = 16, + .adbits = 18, + .ai_fifo_depth = 2047, + .gainlkup = ai_gain_628x, + .ai_speed = 1600, + .ao_fifo_depth = 8191, + .reg_type = ni_reg_628x, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PCI6281] = { + .name = "pci-6281", + .n_adchan = 16, + .adbits = 18, + .ai_fifo_depth = 2047, + .gainlkup = ai_gain_628x, + .ai_speed = 1600, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_ni_M_628x_ao, + .reg_type = ni_reg_628x, + .ao_unipolar = 1, + .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PXI6281] = { + .name = "pxi-6281", + .n_adchan = 16, + .adbits = 18, + .ai_fifo_depth = 2047, + .gainlkup = ai_gain_628x, + .ai_speed = 1600, + .n_aochan = 2, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_ni_M_628x_ao, + .reg_type = ni_reg_628x, + .ao_unipolar = 1, + .ao_speed = 350, + .num_p0_dio_channels = 8, + .caldac = { caldac_none }, + }, + [BOARD_PCI6284] = { + .name = "pci-6284", + .n_adchan = 32, + .adbits = 18, + .ai_fifo_depth = 2047, + .gainlkup = ai_gain_628x, + .ai_speed = 1600, + .reg_type = ni_reg_628x, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PCI6289] = { + .name = "pci-6289", + .n_adchan = 32, + .adbits = 18, + .ai_fifo_depth = 2047, + .gainlkup = ai_gain_628x, + .ai_speed = 1600, + .n_aochan = 4, + .aobits = 16, + .ao_fifo_depth = 8191, + .ao_range_table = &range_ni_M_628x_ao, + .reg_type = ni_reg_628x, + .ao_unipolar = 1, + .ao_speed = 350, + .num_p0_dio_channels = 32, + .caldac = { caldac_none }, + }, + [BOARD_PCI6143] = { + .name = "pci-6143", + .n_adchan = 8, + .adbits = 16, + .ai_fifo_depth = 1024, + .gainlkup = ai_gain_6143, + .ai_speed = 4000, + .reg_type = ni_reg_6143, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug, ad8804_debug }, + }, + [BOARD_PXI6143] = { + .name = "pxi-6143", + .n_adchan = 8, + .adbits = 16, + .ai_fifo_depth = 1024, + .gainlkup = ai_gain_6143, + .ai_speed = 4000, + .reg_type = ni_reg_6143, + .num_p0_dio_channels = 8, + .caldac = { ad8804_debug, ad8804_debug }, }, - { - .device_id = 0x70aa, - .name = "pci-6229", - .n_adchan = 32, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_622x, - .ai_speed = 4000, - .n_aochan = 4, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_622x_ao, - .reg_type = ni_reg_622x, - .ao_unipolar = 0, - .ao_speed = 1200, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70b4, - .name = "pci-6250", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_628x, - .ai_speed = 800, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .reg_type = ni_reg_625x, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70b8, - .name = "pci-6251", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_628x, - .ai_speed = 800, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_625x_ao, - .reg_type = ni_reg_625x, - .ao_unipolar = 0, - .ao_speed = 357, - .num_p0_dio_channels = 8, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x717d, - .name = "pcie-6251", - .n_adchan = 16, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_628x, - .ai_speed = 800, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_625x_ao, - .reg_type = ni_reg_625x, - .ao_unipolar = 0, - .ao_speed = 357, - .num_p0_dio_channels = 8, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70b7, - .name = "pci-6254", - .n_adchan = 32, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_628x, - .ai_speed = 800, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .reg_type = ni_reg_625x, - .ao_unipolar = 0, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70ab, - .name = "pci-6259", - .n_adchan = 32, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_628x, - .ai_speed = 800, - .n_aochan = 4, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_625x_ao, - .reg_type = ni_reg_625x, - .ao_unipolar = 0, - .ao_speed = 357, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x717f, - .name = "pcie-6259", - .n_adchan = 32, - .adbits = 16, - .ai_fifo_depth = 4095, - .gainlkup = ai_gain_628x, - .ai_speed = 800, - .n_aochan = 4, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_625x_ao, - .reg_type = ni_reg_625x, - .ao_unipolar = 0, - .ao_speed = 357, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70b6, - .name = "pci-6280", - .n_adchan = 16, - .adbits = 18, - .ai_fifo_depth = 2047, - .gainlkup = ai_gain_628x, - .ai_speed = 1600, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 8191, - .reg_type = ni_reg_628x, - .ao_unipolar = 0, - .num_p0_dio_channels = 8, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70bd, - .name = "pci-6281", - .n_adchan = 16, - .adbits = 18, - .ai_fifo_depth = 2047, - .gainlkup = ai_gain_628x, - .ai_speed = 1600, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_628x_ao, - .reg_type = ni_reg_628x, - .ao_unipolar = 1, - .ao_speed = 357, - .num_p0_dio_channels = 8, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70bf, - .name = "pxi-6281", - .n_adchan = 16, - .adbits = 18, - .ai_fifo_depth = 2047, - .gainlkup = ai_gain_628x, - .ai_speed = 1600, - .n_aochan = 2, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_628x_ao, - .reg_type = ni_reg_628x, - .ao_unipolar = 1, - .ao_speed = 357, - .num_p0_dio_channels = 8, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70bc, - .name = "pci-6284", - .n_adchan = 32, - .adbits = 18, - .ai_fifo_depth = 2047, - .gainlkup = ai_gain_628x, - .ai_speed = 1600, - .n_aochan = 0, - .aobits = 0, - .ao_fifo_depth = 0, - .reg_type = ni_reg_628x, - .ao_unipolar = 0, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70ac, - .name = "pci-6289", - .n_adchan = 32, - .adbits = 18, - .ai_fifo_depth = 2047, - .gainlkup = ai_gain_628x, - .ai_speed = 1600, - .n_aochan = 4, - .aobits = 16, - .ao_fifo_depth = 8191, - .ao_range_table = &range_ni_M_628x_ao, - .reg_type = ni_reg_628x, - .ao_unipolar = 1, - .ao_speed = 357, - .num_p0_dio_channels = 32, - .caldac = {caldac_none}, - .has_8255 = 0, - }, - { - .device_id = 0x70C0, - .name = "pci-6143", - .n_adchan = 8, - .adbits = 16, - .ai_fifo_depth = 1024, - .alwaysdither = 0, - .gainlkup = ai_gain_6143, - .ai_speed = 4000, - .n_aochan = 0, - .aobits = 0, - .reg_type = ni_reg_6143, - .ao_unipolar = 0, - .ao_fifo_depth = 0, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug, ad8804_debug}, - }, - { - .device_id = 0x710D, - .name = "pxi-6143", - .n_adchan = 8, - .adbits = 16, - .ai_fifo_depth = 1024, - .alwaysdither = 0, - .gainlkup = ai_gain_6143, - .ai_speed = 4000, - .n_aochan = 0, - .aobits = 0, - .reg_type = ni_reg_6143, - .ao_unipolar = 0, - .ao_fifo_depth = 0, - .num_p0_dio_channels = 8, - .caldac = {ad8804_debug, ad8804_debug}, - }, -}; - -#define n_pcimio_boards ARRAY_SIZE(ni_boards) - -static int pcimio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcimio_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcimio = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = pcimio_attach, - .detach = pcimio_detach, -}; - -static int __devinit driver_pcimio_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, driver_pcimio.driver_name); -} - -static void __devexit driver_pcimio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static struct pci_driver driver_pcimio_pci_driver = { - .id_table = ni_pci_table, - .probe = &driver_pcimio_pci_probe, - .remove = __devexit_p(&driver_pcimio_pci_remove) }; -static int __init driver_pcimio_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_pcimio); - if (retval < 0) - return retval; - - driver_pcimio_pci_driver.name = (char *)driver_pcimio.driver_name; - return pci_register_driver(&driver_pcimio_pci_driver); -} - -static void __exit driver_pcimio_cleanup_module(void) -{ - pci_unregister_driver(&driver_pcimio_pci_driver); - comedi_driver_unregister(&driver_pcimio); -} - -module_init(driver_pcimio_init_module); -module_exit(driver_pcimio_cleanup_module); - struct ni_private { NI_PRIVATE_COMMON}; -#define devpriv ((struct ni_private *)dev->private) /* How we access registers */ @@ -1302,6 +1068,7 @@ NI_PRIVATE_COMMON}; static void e_series_win_out(struct comedi_device *dev, uint16_t data, int reg) { + struct ni_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&devpriv->window_lock, flags); @@ -1312,6 +1079,7 @@ static void e_series_win_out(struct comedi_device *dev, uint16_t data, int reg) static uint16_t e_series_win_in(struct comedi_device *dev, int reg) { + struct ni_private *devpriv = dev->private; unsigned long flags; uint16_t ret; @@ -1326,7 +1094,9 @@ static uint16_t e_series_win_in(struct comedi_device *dev, int reg) static void m_series_stc_writew(struct comedi_device *dev, uint16_t data, int reg) { + struct ni_private *devpriv = dev->private; unsigned offset; + switch (reg) { case ADC_FIFO_Clear: offset = M_Offset_AI_FIFO_Clear; @@ -1408,9 +1178,9 @@ static void m_series_stc_writew(struct comedi_device *dev, uint16_t data, offset = M_Offset_AO_FIFO_Clear; break; case DIO_Control_Register: - printk - ("%s: FIXME: register 0x%x does not map cleanly on to m-series boards.\n", - __func__, reg); + dev_dbg(dev->class_dev, + "%s: FIXME: register 0x%x does not map cleanly on to m-series boards.\n", + __func__, reg); return; break; case G_Autoincrement_Register(0): @@ -1470,8 +1240,9 @@ static void m_series_stc_writew(struct comedi_device *dev, uint16_t data, /* FIXME: DIO_Output_Register (16 bit reg) is replaced by M_Offset_Static_Digital_Output (32 bit) and M_Offset_SCXI_Serial_Data_Out (8 bit) */ default: - printk("%s: bug! unhandled register=0x%x in switch.\n", - __func__, reg); + dev_warn(dev->class_dev, + "%s: bug! unhandled register=0x%x in switch.\n", + __func__, reg); BUG(); return; break; @@ -1481,7 +1252,9 @@ static void m_series_stc_writew(struct comedi_device *dev, uint16_t data, static uint16_t m_series_stc_readw(struct comedi_device *dev, int reg) { + struct ni_private *devpriv = dev->private; unsigned offset; + switch (reg) { case AI_Status_1_Register: offset = M_Offset_AI_Status_1; @@ -1505,8 +1278,9 @@ static uint16_t m_series_stc_readw(struct comedi_device *dev, int reg) offset = M_Offset_G01_Status; break; default: - printk("%s: bug! unhandled register=0x%x in switch.\n", - __func__, reg); + dev_warn(dev->class_dev, + "%s: bug! unhandled register=0x%x in switch.\n", + __func__, reg); BUG(); return 0; break; @@ -1517,7 +1291,9 @@ static uint16_t m_series_stc_readw(struct comedi_device *dev, int reg) static void m_series_stc_writel(struct comedi_device *dev, uint32_t data, int reg) { + struct ni_private *devpriv = dev->private; unsigned offset; + switch (reg) { case AI_SC_Load_A_Registers: offset = M_Offset_AI_SC_Load_A; @@ -1547,8 +1323,9 @@ static void m_series_stc_writel(struct comedi_device *dev, uint32_t data, offset = M_Offset_G1_Load_B; break; default: - printk("%s: bug! unhandled register=0x%x in switch.\n", - __func__, reg); + dev_warn(dev->class_dev, + "%s: bug! unhandled register=0x%x in switch.\n", + __func__, reg); BUG(); return; break; @@ -1558,7 +1335,9 @@ static void m_series_stc_writel(struct comedi_device *dev, uint32_t data, static uint32_t m_series_stc_readl(struct comedi_device *dev, int reg) { + struct ni_private *devpriv = dev->private; unsigned offset; + switch (reg) { case G_HW_Save_Register(0): offset = M_Offset_G0_HW_Save; @@ -1573,8 +1352,9 @@ static uint32_t m_series_stc_readl(struct comedi_device *dev, int reg) offset = M_Offset_G1_Save; break; default: - printk("%s: bug! unhandled register=0x%x in switch.\n", - __func__, reg); + dev_warn(dev->class_dev, + "%s: bug! unhandled register=0x%x in switch.\n", + __func__, reg); BUG(); return 0; break; @@ -1589,7 +1369,6 @@ static uint32_t m_series_stc_readl(struct comedi_device *dev, int reg) #include "ni_mio_common.c" -static int pcimio_find_device(struct comedi_device *dev, int bus, int slot); static int pcimio_ai_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); static int pcimio_ao_change(struct comedi_device *dev, @@ -1606,6 +1385,7 @@ static int pcimio_dio_change(struct comedi_device *dev, static void m_series_init_eeprom_buffer(struct comedi_device *dev) { + struct ni_private *devpriv = dev->private; static const int Start_Cal_EEPROM = 0x400; static const unsigned window_size = 10; static const int serial_number_eeprom_offset = 0x4; @@ -1632,9 +1412,8 @@ static void m_series_init_eeprom_buffer(struct comedi_device *dev) } devpriv->serial_number = be32_to_cpu(devpriv->serial_number); - for (i = 0; i < M_SERIES_EEPROM_SIZE; ++i) { + for (i = 0; i < M_SERIES_EEPROM_SIZE; ++i) devpriv->eeprom_buffer[i] = ni_readb(Start_Cal_EEPROM + i); - } writel(old_iodwbsr1_bits, devpriv->mite->mite_io_addr + MITE_IODWBSR_1); writel(old_iodwbsr_bits, devpriv->mite->mite_io_addr + MITE_IODWBSR); @@ -1644,6 +1423,9 @@ 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); + struct ni_private *devpriv = dev->private; + /* Disable interrupts */ devpriv->stc_writew(dev, 0, Interrupt_Control_Register); @@ -1652,7 +1434,8 @@ static void init_6143(struct comedi_device *dev) ni_writeb(0x80, PipelineDelay_6143); /* Set EOCMode, ADCMode and pipelinedelay */ ni_writeb(0x00, EOC_Set_6143); /* Set EOC Delay */ - ni_writel(boardtype.ai_fifo_depth / 2, AIFIFO_Flag_6143); /* Set the FIFO half full level */ + /* Set the FIFO half full level */ + ni_writel(board->ai_fifo_depth / 2, AIFIFO_Flag_6143); /* Strobe Relay disable bit */ devpriv->ai_calib_source_enabled = 0; @@ -1661,44 +1444,57 @@ static void init_6143(struct comedi_device *dev) ni_writew(devpriv->ai_calib_source, Calibration_Channel_6143); } -/* cleans up allocated resources */ -static int pcimio_detach(struct comedi_device *dev) +static void pcimio_detach(struct comedi_device *dev) { + struct ni_private *devpriv = dev->private; + mio_common_detach(dev); - if (dev->irq) { + if (dev->irq) free_irq(dev->irq, dev); - } - if (dev->private) { + if (devpriv) { mite_free_ring(devpriv->ai_mite_ring); mite_free_ring(devpriv->ao_mite_ring); mite_free_ring(devpriv->cdo_mite_ring); mite_free_ring(devpriv->gpct_mite_ring[0]); mite_free_ring(devpriv->gpct_mite_ring[1]); - if (devpriv->mite) + if (devpriv->mite) { mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); + } } - - return 0; + comedi_pci_disable(dev); } -static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pcimio_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct ni_board_struct *board = NULL; + struct ni_private *devpriv; + unsigned int irq; int ret; - printk("comedi%d: ni_pcimio:", dev->minor); + if (context < ARRAY_SIZE(ni_boards)) + board = &ni_boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; - ret = ni_alloc_private(dev); - if (ret < 0) + ret = comedi_pci_enable(dev); + if (ret) return ret; - ret = pcimio_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) + ret = ni_alloc_private(dev); + if (ret) return ret; + devpriv = dev->private; - printk(" %s", boardtype.name); - dev->board_name = boardtype.name; + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; - if (boardtype.reg_type & ni_reg_m_series_mask) { + if (board->reg_type & ni_reg_m_series_mask) { devpriv->stc_writew = &m_series_stc_writew; devpriv->stc_readw = &m_series_stc_readw; devpriv->stc_writel = &m_series_stc_writel; @@ -1712,10 +1508,10 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) ret = mite_setup(devpriv->mite); if (ret < 0) { - printk(" error setting up mite\n"); + pr_warn("error setting up mite\n"); return ret; } - comedi_set_hw_dev(dev, &devpriv->mite->pcidev->dev); + devpriv->ai_mite_ring = mite_alloc_ring(devpriv->mite); if (devpriv->ai_mite_ring == NULL) return -ENOMEM; @@ -1732,26 +1528,20 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (devpriv->gpct_mite_ring[1] == NULL) return -ENOMEM; - if (boardtype.reg_type & ni_reg_m_series_mask) + if (board->reg_type & ni_reg_m_series_mask) m_series_init_eeprom_buffer(dev); - if (boardtype.reg_type == ni_reg_6143) + if (board->reg_type == ni_reg_6143) init_6143(dev); - dev->irq = mite_irq(devpriv->mite); - - if (dev->irq == 0) { - printk(" unknown irq (bad)\n"); - } else { - printk(" ( irq = %u )", dev->irq); - ret = request_irq(dev->irq, ni_E_interrupt, NI_E_IRQ_FLAGS, - DRV_NAME, dev); - if (ret < 0) { - printk(" irq not available\n"); - dev->irq = 0; - } + irq = mite_irq(devpriv->mite); + if (irq) { + ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS, + dev->board_name, dev); + if (ret == 0) + dev->irq = irq; } - ret = ni_E_init(dev, it); + ret = ni_E_init(dev); if (ret < 0) return ret; @@ -1761,43 +1551,16 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->subdevices[NI_GPCT_SUBDEV(1)].buf_change = &pcimio_gpct1_change; dev->subdevices[NI_DIO_SUBDEV].buf_change = &pcimio_dio_change; - return ret; -} - -static int pcimio_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - - for (i = 0; i < n_pcimio_boards; i++) { - if (mite_device_id(mite) == ni_boards[i].device_id) { - dev->board_ptr = ni_boards + i; - devpriv->mite = mite; - - return 0; - } - } - } - printk("no device found\n"); - mite_list_devices(); - return -EIO; + return 0; } static int pcimio_ai_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { + struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->ai_mite_ring, s->async); + ret = mite_buf_change(devpriv->ai_mite_ring, s); if (ret < 0) return ret; @@ -1807,9 +1570,10 @@ static int pcimio_ai_change(struct comedi_device *dev, static int pcimio_ao_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { + struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->ao_mite_ring, s->async); + ret = mite_buf_change(devpriv->ao_mite_ring, s); if (ret < 0) return ret; @@ -1820,9 +1584,10 @@ static int pcimio_gpct0_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { + struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->gpct_mite_ring[0], s->async); + ret = mite_buf_change(devpriv->gpct_mite_ring[0], s); if (ret < 0) return ret; @@ -1833,9 +1598,10 @@ static int pcimio_gpct1_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { + struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->gpct_mite_ring[1], s->async); + ret = mite_buf_change(devpriv->gpct_mite_ring[1], s); if (ret < 0) return ret; @@ -1845,15 +1611,96 @@ static int pcimio_gpct1_change(struct comedi_device *dev, static int pcimio_dio_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { + struct ni_private *devpriv = dev->private; int ret; - ret = mite_buf_change(devpriv->cdo_mite_ring, s->async); + ret = mite_buf_change(devpriv->cdo_mite_ring, s); if (ret < 0) return ret; return 0; } +static struct comedi_driver ni_pcimio_driver = { + .driver_name = "ni_pcimio", + .module = THIS_MODULE, + .auto_attach = pcimio_auto_attach, + .detach = pcimio_detach, +}; + +static int ni_pcimio_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &ni_pcimio_driver, id->driver_data); +} + +static const struct pci_device_id ni_pcimio_pci_table[] = { + { PCI_VDEVICE(NI, 0x0162), BOARD_PCIMIO_16XE_50 }, /* 0x1620? */ + { PCI_VDEVICE(NI, 0x1170), BOARD_PCIMIO_16XE_10 }, + { PCI_VDEVICE(NI, 0x1180), BOARD_PCIMIO_16E_1 }, + { PCI_VDEVICE(NI, 0x1190), BOARD_PCIMIO_16E_4 }, + { PCI_VDEVICE(NI, 0x11b0), BOARD_PXI6070E }, + { PCI_VDEVICE(NI, 0x11c0), BOARD_PXI6040E }, + { PCI_VDEVICE(NI, 0x11d0), BOARD_PXI6030E }, + { PCI_VDEVICE(NI, 0x1270), BOARD_PCI6032E }, + { PCI_VDEVICE(NI, 0x1330), BOARD_PCI6031E }, + { PCI_VDEVICE(NI, 0x1340), BOARD_PCI6033E }, + { PCI_VDEVICE(NI, 0x1350), BOARD_PCI6071E }, + { PCI_VDEVICE(NI, 0x14e0), BOARD_PCI6110 }, + { PCI_VDEVICE(NI, 0x14f0), BOARD_PCI6111 }, + { PCI_VDEVICE(NI, 0x1580), BOARD_PXI6031E }, + { PCI_VDEVICE(NI, 0x15b0), BOARD_PXI6071E }, + { PCI_VDEVICE(NI, 0x1880), BOARD_PCI6711 }, + { PCI_VDEVICE(NI, 0x1870), BOARD_PCI6713 }, + { PCI_VDEVICE(NI, 0x18b0), BOARD_PCI6052E }, + { PCI_VDEVICE(NI, 0x18c0), BOARD_PXI6052E }, + { PCI_VDEVICE(NI, 0x2410), BOARD_PCI6733 }, + { PCI_VDEVICE(NI, 0x2420), BOARD_PXI6733 }, + { PCI_VDEVICE(NI, 0x2430), BOARD_PCI6731 }, + { PCI_VDEVICE(NI, 0x2890), BOARD_PCI6036E }, + { PCI_VDEVICE(NI, 0x28c0), BOARD_PCI6014 }, + { PCI_VDEVICE(NI, 0x2a60), BOARD_PCI6023E }, + { PCI_VDEVICE(NI, 0x2a70), BOARD_PCI6024E }, + { PCI_VDEVICE(NI, 0x2a80), BOARD_PCI6025E }, + { PCI_VDEVICE(NI, 0x2ab0), BOARD_PXI6025E }, + { PCI_VDEVICE(NI, 0x2b80), BOARD_PXI6713 }, + { PCI_VDEVICE(NI, 0x2b90), BOARD_PXI6711 }, + { PCI_VDEVICE(NI, 0x2c80), BOARD_PCI6035E }, + { PCI_VDEVICE(NI, 0x2ca0), BOARD_PCI6034E }, + { PCI_VDEVICE(NI, 0x70aa), BOARD_PCI6229 }, + { PCI_VDEVICE(NI, 0x70ab), BOARD_PCI6259 }, + { PCI_VDEVICE(NI, 0x70ac), BOARD_PCI6289 }, + { PCI_VDEVICE(NI, 0x70af), BOARD_PCI6221 }, + { PCI_VDEVICE(NI, 0x70b0), BOARD_PCI6220 }, + { PCI_VDEVICE(NI, 0x70b4), BOARD_PCI6250 }, + { PCI_VDEVICE(NI, 0x70b6), BOARD_PCI6280 }, + { PCI_VDEVICE(NI, 0x70b7), BOARD_PCI6254 }, + { PCI_VDEVICE(NI, 0x70b8), BOARD_PCI6251 }, + { PCI_VDEVICE(NI, 0x70bc), BOARD_PCI6284 }, + { PCI_VDEVICE(NI, 0x70bd), BOARD_PCI6281 }, + { PCI_VDEVICE(NI, 0x70bf), BOARD_PXI6281 }, + { PCI_VDEVICE(NI, 0x70c0), BOARD_PCI6143 }, + { PCI_VDEVICE(NI, 0x70f2), BOARD_PCI6224 }, + { PCI_VDEVICE(NI, 0x70f3), BOARD_PXI6224 }, + { PCI_VDEVICE(NI, 0x710d), BOARD_PXI6143 }, + { PCI_VDEVICE(NI, 0x716c), BOARD_PCI6225 }, + { PCI_VDEVICE(NI, 0x716d), BOARD_PXI6225 }, + { PCI_VDEVICE(NI, 0x717f), BOARD_PCIE6259 }, + { PCI_VDEVICE(NI, 0x71bc), BOARD_PCI6221_37PIN }, + { PCI_VDEVICE(NI, 0x717d), BOARD_PCIE6251 }, + { PCI_VDEVICE(NI, 0x72e8), BOARD_PXIE6251 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, ni_pcimio_pci_table); + +static struct pci_driver ni_pcimio_pci_driver = { + .name = "ni_pcimio", + .id_table = ni_pcimio_pci_table, + .probe = ni_pcimio_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_stc.h b/drivers/staging/comedi/drivers/ni_stc.h index 504ea715533..f0630b7897b 100644 --- a/drivers/staging/comedi/drivers/ni_stc.h +++ b/drivers/staging/comedi/drivers/ni_stc.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* @@ -1421,10 +1416,6 @@ struct ni_board_struct { enum caldac_enum caldac[3]; }; -#define n_ni_boards (sizeof(ni_boards)/sizeof(struct ni_board_struct)) - -#define boardtype (*(struct ni_board_struct *)dev->board_ptr) - #define MAX_N_AO_CHAN 8 #define NUM_GPCT 2 @@ -1500,7 +1491,7 @@ struct ni_board_struct { unsigned short pwm_up_count; \ unsigned short pwm_down_count; \ \ - short ai_fifo_buffer[0x2000]; \ + unsigned short ai_fifo_buffer[0x2000]; \ uint8_t eeprom_buffer[M_SERIES_EEPROM_SIZE]; \ uint32_t serial_number; \ \ diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c index 98f87897e2a..92691b491c2 100644 --- a/drivers/staging/comedi/drivers/ni_tio.c +++ b/drivers/staging/comedi/drivers/ni_tio.c @@ -13,10 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -48,16 +44,15 @@ TODO: Support use of both banks X and Y */ +#include <linux/module.h> +#include <linux/slab.h> + #include "ni_tio_internal.h" static uint64_t ni_tio_clock_period_ps(const struct ni_gpct *counter, unsigned generic_clock_source); static unsigned ni_tio_generic_clock_src_select(const struct ni_gpct *counter); -MODULE_AUTHOR("Comedi <comedi@comedi.org>"); -MODULE_DESCRIPTION("Comedi support for NI general-purpose counters"); -MODULE_LICENSE("GPL"); - static inline enum Gi_Counting_Mode_Reg_Bits Gi_Alternate_Sync_Bit(enum ni_gpct_variant variant) @@ -276,20 +271,7 @@ static inline unsigned NI_660x_RTSI_Second_Gate_Select(unsigned n) } static const unsigned int counter_status_mask = - COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING; - -static int __init ni_tio_init_module(void) -{ - return 0; -} - -module_init(ni_tio_init_module); - -static void __exit ni_tio_cleanup_module(void) -{ -} - -module_exit(ni_tio_cleanup_module); + COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING; struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device *dev, void (*write_register) (struct @@ -363,74 +345,64 @@ static int ni_tio_second_gate_registers_present(const struct ni_gpct_device static void ni_tio_reset_count_and_disarm(struct ni_gpct *counter) { - write_register(counter, Gi_Reset_Bit(counter->counter_index), - NITIO_Gxx_Joint_Reset_Reg(counter->counter_index)); + unsigned cidx = counter->counter_index; + + write_register(counter, Gi_Reset_Bit(cidx), NITIO_RESET_REG(cidx)); } void ni_tio_init_counter(struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; ni_tio_reset_count_and_disarm(counter); + /* initialize counter registers */ - counter_dev->regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)] = - 0x0; - write_register(counter, - counter_dev-> - regs[NITIO_Gi_Autoincrement_Reg(counter->counter_index)], - NITIO_Gi_Autoincrement_Reg(counter->counter_index)); - ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), + counter_dev->regs[NITIO_AUTO_INC_REG(cidx)] = 0x0; + write_register(counter, counter_dev->regs[NITIO_AUTO_INC_REG(cidx)], + NITIO_AUTO_INC_REG(cidx)); + + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), ~0, Gi_Synchronize_Gate_Bit); - ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), ~0, - 0); - counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = 0x0; - write_register(counter, - counter_dev-> - regs[NITIO_Gi_LoadA_Reg(counter->counter_index)], - NITIO_Gi_LoadA_Reg(counter->counter_index)); - counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = 0x0; - write_register(counter, - counter_dev-> - regs[NITIO_Gi_LoadB_Reg(counter->counter_index)], - NITIO_Gi_LoadB_Reg(counter->counter_index)); - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), ~0, - 0); - if (ni_tio_counting_mode_registers_present(counter_dev)) { - ni_tio_set_bits(counter, - NITIO_Gi_Counting_Mode_Reg(counter-> - counter_index), ~0, - 0); - } + + ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), ~0, 0); + + counter_dev->regs[NITIO_LOADA_REG(cidx)] = 0x0; + write_register(counter, counter_dev->regs[NITIO_LOADA_REG(cidx)], + NITIO_LOADA_REG(cidx)); + + counter_dev->regs[NITIO_LOADB_REG(cidx)] = 0x0; + write_register(counter, counter_dev->regs[NITIO_LOADB_REG(cidx)], + NITIO_LOADB_REG(cidx)); + + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), ~0, 0); + + if (ni_tio_counting_mode_registers_present(counter_dev)) + ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), ~0, 0); + if (ni_tio_second_gate_registers_present(counter_dev)) { - counter_dev-> - regs[NITIO_Gi_Second_Gate_Reg(counter->counter_index)] = - 0x0; + counter_dev->regs[NITIO_GATE2_REG(cidx)] = 0x0; write_register(counter, - counter_dev-> - regs[NITIO_Gi_Second_Gate_Reg - (counter->counter_index)], - NITIO_Gi_Second_Gate_Reg(counter-> - counter_index)); + counter_dev->regs[NITIO_GATE2_REG(cidx)], + NITIO_GATE2_REG(cidx)); } - ni_tio_set_bits(counter, - NITIO_Gi_DMA_Config_Reg(counter->counter_index), ~0, - 0x0); - ni_tio_set_bits(counter, - NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index), - ~0, 0x0); + + ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), ~0, 0x0); + + ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), ~0, 0x0); } EXPORT_SYMBOL_GPL(ni_tio_init_counter); static unsigned int ni_tio_counter_status(struct ni_gpct *counter) { - unsigned int status = 0; + unsigned cidx = counter->counter_index; const unsigned bits = read_register(counter, - NITIO_Gxx_Status_Reg(counter-> - counter_index)); - if (bits & Gi_Armed_Bit(counter->counter_index)) { + NITIO_SHARED_STATUS_REG(cidx)); + unsigned int status = 0; + + if (bits & Gi_Armed_Bit(cidx)) { status |= COMEDI_COUNTER_ARMED; - if (bits & Gi_Counting_Bit(counter->counter_index)) + if (bits & Gi_Counting_Bit(cidx)) status |= COMEDI_COUNTER_COUNTING; } return status; @@ -439,8 +411,8 @@ static unsigned int ni_tio_counter_status(struct ni_gpct *counter) static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned counting_mode_reg = - NITIO_Gi_Counting_Mode_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned counting_mode_reg = NITIO_CNT_MODE_REG(cidx); static const uint64_t min_normal_sync_period_ps = 25000; const uint64_t clock_period_ps = ni_tio_clock_period_ps(counter, ni_tio_generic_clock_src_select @@ -477,6 +449,7 @@ static void ni_tio_set_sync_mode(struct ni_gpct *counter, int force_alt_sync) static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; unsigned mode_reg_mask; unsigned mode_reg_values; unsigned input_select_bits = 0; @@ -503,7 +476,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) default: break; } - ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), mode_reg_mask, mode_reg_values); if (ni_tio_counting_mode_registers_present(counter_dev)) { @@ -516,15 +489,13 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) Gi_Index_Phase_Bitshift) & Gi_Index_Phase_Mask; if (mode & NI_GPCT_INDEX_ENABLE_BIT) counting_mode_bits |= Gi_Index_Mode_Bit; - ni_tio_set_bits(counter, - NITIO_Gi_Counting_Mode_Reg(counter-> - counter_index), + ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), Gi_Counting_Mode_Mask | Gi_Index_Phase_Mask | Gi_Index_Mode_Bit, counting_mode_bits); ni_tio_set_sync_mode(counter, 0); } - ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Up_Down_Mask, (mode >> NI_GPCT_COUNTING_DIRECTION_SHIFT) << Gi_Up_Down_Shift); @@ -533,8 +504,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) input_select_bits |= Gi_Or_Gate_Bit; if (mode & NI_GPCT_INVERT_OUTPUT_BIT) input_select_bits |= Gi_Output_Polarity_Bit; - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Gate_Select_Load_Source_Bit | Gi_Or_Gate_Bit | Gi_Output_Polarity_Bit, input_select_bits); @@ -544,7 +514,7 @@ static int ni_tio_set_counter_mode(struct ni_gpct *counter, unsigned mode) int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) { struct ni_gpct_device *counter_dev = counter->counter_dev; - + unsigned cidx = counter->counter_index; unsigned command_transient_bits = 0; if (arm) { @@ -582,9 +552,7 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) } break; } - ni_tio_set_bits(counter, - NITIO_Gi_Counting_Mode_Reg - (counter->counter_index), + ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), Gi_HW_Arm_Select_Mask (counter_dev->variant) | Gi_HW_Arm_Enable_Bit, @@ -593,8 +561,7 @@ int ni_tio_arm(struct ni_gpct *counter, int arm, unsigned start_trigger) } else { command_transient_bits |= Gi_Disarm_Bit; } - ni_tio_set_bits_transient(counter, - NITIO_Gi_Command_Reg(counter->counter_index), + ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx), 0, 0, command_transient_bits); return 0; } @@ -718,8 +685,8 @@ static void ni_tio_set_source_subselect(struct ni_gpct *counter, unsigned int clock_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); if (counter_dev->variant != ni_gpct_variant_m_series) return; @@ -748,6 +715,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, unsigned int period_ns) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; unsigned input_select_bits = 0; static const uint64_t pico_per_nano = 1000; @@ -767,8 +735,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, } if (clock_source & NI_GPCT_INVERT_CLOCK_SRC_BIT) input_select_bits |= Gi_Source_Polarity_Bit; - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Source_Select_Mask | Gi_Source_Polarity_Bit, input_select_bits); ni_tio_set_source_subselect(counter, clock_source); @@ -792,9 +759,7 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, return -EINVAL; break; } - ni_tio_set_bits(counter, - NITIO_Gi_Counting_Mode_Reg(counter-> - counter_index), + ni_tio_set_bits(counter, NITIO_CNT_MODE_REG(cidx), Gi_Prescale_X2_Bit(counter_dev->variant) | Gi_Prescale_X8_Bit(counter_dev->variant), counting_mode_bits); @@ -807,15 +772,12 @@ static int ni_tio_set_clock_src(struct ni_gpct *counter, static unsigned ni_tio_clock_src_modifiers(const struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned counting_mode_bits = ni_tio_get_soft_copy(counter, - NITIO_Gi_Counting_Mode_Reg - (counter-> - counter_index)); + unsigned cidx = counter->counter_index; + const unsigned counting_mode_bits = + ni_tio_get_soft_copy(counter, NITIO_CNT_MODE_REG(cidx)); unsigned bits = 0; - if (ni_tio_get_soft_copy(counter, - NITIO_Gi_Input_Select_Reg - (counter->counter_index)) & + if (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) & Gi_Source_Polarity_Bit) bits |= NI_GPCT_INVERT_CLOCK_SRC_BIT; if (counting_mode_bits & Gi_Prescale_X2_Bit(counter_dev->variant)) @@ -828,15 +790,13 @@ static unsigned ni_tio_clock_src_modifiers(const struct ni_gpct *counter) static unsigned ni_m_series_clock_src_select(const struct ni_gpct *counter) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); unsigned clock_source = 0; unsigned i; - const unsigned input_select = (ni_tio_get_soft_copy(counter, - NITIO_Gi_Input_Select_Reg - (counter->counter_index)) - & Gi_Source_Select_Mask) >> - Gi_Source_Select_Shift; + const unsigned input_select = + (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) & + Gi_Source_Select_Mask) >> Gi_Source_Select_Shift; switch (input_select) { case NI_M_Series_Timebase_1_Clock: @@ -896,12 +856,11 @@ static unsigned ni_m_series_clock_src_select(const struct ni_gpct *counter) static unsigned ni_660x_clock_src_select(const struct ni_gpct *counter) { unsigned clock_source = 0; + unsigned cidx = counter->counter_index; + const unsigned input_select = + (ni_tio_get_soft_copy(counter, NITIO_INPUT_SEL_REG(cidx)) & + Gi_Source_Select_Mask) >> Gi_Source_Select_Shift; unsigned i; - const unsigned input_select = (ni_tio_get_soft_copy(counter, - NITIO_Gi_Input_Select_Reg - (counter->counter_index)) - & Gi_Source_Select_Mask) >> - Gi_Source_Select_Shift; switch (input_select) { case NI_660x_Timebase_1_Clock: @@ -1023,6 +982,7 @@ static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter, unsigned int gate_source) { const unsigned mode_mask = Gi_Gate_Polarity_Bit | Gi_Gating_Mode_Mask; + unsigned cidx = counter->counter_index; unsigned mode_values = 0; if (gate_source & CR_INVERT) @@ -1031,7 +991,7 @@ static void ni_tio_set_first_gate_modifiers(struct ni_gpct *counter, mode_values |= Gi_Rising_Edge_Gating_Bits; else mode_values |= Gi_Level_Gating_Bits; - ni_tio_set_bits(counter, NITIO_Gi_Mode_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), mode_mask, mode_values); } @@ -1039,6 +999,7 @@ static int ni_660x_set_first_gate(struct ni_gpct *counter, unsigned int gate_source) { const unsigned selected_gate = CR_CHAN(gate_source); + unsigned cidx = counter->counter_index; /* bits of selected_gate that may be meaningful to input select register */ const unsigned selected_gate_mask = 0x1f; unsigned ni_660x_gate_select; @@ -1076,8 +1037,7 @@ static int ni_660x_set_first_gate(struct ni_gpct *counter, return -EINVAL; break; } - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Gate_Select_Mask, Gi_Gate_Select_Bits(ni_660x_gate_select)); return 0; @@ -1087,6 +1047,7 @@ static int ni_m_series_set_first_gate(struct ni_gpct *counter, unsigned int gate_source) { const unsigned selected_gate = CR_CHAN(gate_source); + unsigned cidx = counter->counter_index; /* bits of selected_gate that may be meaningful to input select register */ const unsigned selected_gate_mask = 0x1f; unsigned ni_m_series_gate_select; @@ -1125,8 +1086,7 @@ static int ni_m_series_set_first_gate(struct ni_gpct *counter, return -EINVAL; break; } - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Gate_Select_Mask, Gi_Gate_Select_Bits(ni_m_series_gate_select)); return 0; @@ -1136,8 +1096,8 @@ static int ni_660x_set_second_gate(struct ni_gpct *counter, unsigned int gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); const unsigned selected_second_gate = CR_CHAN(gate_source); /* bits of second_gate that may be meaningful to second gate register */ static const unsigned selected_second_gate_mask = 0x1f; @@ -1195,8 +1155,8 @@ static int ni_m_series_set_second_gate(struct ni_gpct *counter, unsigned int gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); const unsigned selected_second_gate = CR_CHAN(gate_source); /* bits of second_gate that may be meaningful to second gate register */ static const unsigned selected_second_gate_mask = 0x1f; @@ -1223,15 +1183,13 @@ int ni_tio_set_gate_src(struct ni_gpct *counter, unsigned gate_index, unsigned int gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); switch (gate_index) { case 0: if (CR_CHAN(gate_source) == NI_GPCT_DISABLED_GATE_SELECT) { - ni_tio_set_bits(counter, - NITIO_Gi_Mode_Reg(counter-> - counter_index), + ni_tio_set_bits(counter, NITIO_MODE_REG(cidx), Gi_Gating_Mode_Mask, Gi_Gating_Disabled_Bits); return 0; @@ -1293,11 +1251,12 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index, unsigned int source) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; if (counter_dev->variant == ni_gpct_variant_m_series) { unsigned int abz_reg, shift, mask; - abz_reg = NITIO_Gi_ABZ_Reg(counter->counter_index); + abz_reg = NITIO_ABZ_REG(cidx); switch (index) { case NI_GPCT_SOURCE_ENCODER_A: shift = 10; @@ -1320,7 +1279,6 @@ static int ni_tio_set_other_src(struct ni_gpct *counter, unsigned index, counter_dev->regs[abz_reg] &= ~mask; counter_dev->regs[abz_reg] |= (source << shift) & mask; write_register(counter, counter_dev->regs[abz_reg], abz_reg); -/* printk("%s %x %d %d\n", __func__, counter_dev->regs[abz_reg], index, source); */ return 0; } return -EINVAL; @@ -1492,12 +1450,10 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, unsigned int *gate_source) { struct ni_gpct_device *counter_dev = counter->counter_dev; - const unsigned mode_bits = ni_tio_get_soft_copy(counter, - NITIO_Gi_Mode_Reg - (counter-> - counter_index)); - const unsigned second_gate_reg = - NITIO_Gi_Second_Gate_Reg(counter->counter_index); + unsigned cidx = counter->counter_index; + const unsigned mode_bits = + ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx)); + const unsigned second_gate_reg = NITIO_GATE2_REG(cidx); unsigned gate_select_bits; switch (gate_index) { @@ -1509,8 +1465,7 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, } else { gate_select_bits = (ni_tio_get_soft_copy(counter, - NITIO_Gi_Input_Select_Reg - (counter->counter_index)) & + NITIO_INPUT_SEL_REG(cidx)) & Gi_Gate_Select_Mask) >> Gi_Gate_Select_Shift; } switch (counter_dev->variant) { @@ -1578,9 +1533,13 @@ static int ni_tio_get_gate_src(struct ni_gpct *counter, unsigned gate_index, return 0; } -int ni_tio_insn_config(struct ni_gpct *counter, - struct comedi_insn *insn, unsigned int *data) +int ni_tio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct ni_gpct *counter = s->private; + switch (data[0]) { case INSN_CONFIG_SET_COUNTER_MODE: return ni_tio_set_counter_mode(counter, data[1]); @@ -1624,11 +1583,15 @@ int ni_tio_insn_config(struct ni_gpct *counter, } EXPORT_SYMBOL_GPL(ni_tio_insn_config); -int ni_tio_rinsn(struct ni_gpct *counter, struct comedi_insn *insn, - unsigned int *data) +int ni_tio_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct ni_gpct *counter = s->private; struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned channel = CR_CHAN(insn->chanspec); + unsigned cidx = counter->counter_index; unsigned first_read; unsigned second_read; unsigned correct_read; @@ -1637,65 +1600,57 @@ int ni_tio_rinsn(struct ni_gpct *counter, struct comedi_insn *insn, return 0; switch (channel) { case 0: - ni_tio_set_bits(counter, - NITIO_Gi_Command_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Save_Trace_Bit, 0); - ni_tio_set_bits(counter, - NITIO_Gi_Command_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Save_Trace_Bit, Gi_Save_Trace_Bit); /* The count doesn't get latched until the next clock edge, so it is possible the count may change (once) while we are reading. Since the read of the SW_Save_Reg isn't atomic (apparently even when it's a 32 bit register according to 660x docs), we need to read twice and make sure the reading hasn't changed. If it has, a third read will be correct since the count value will definitely have latched by then. */ - first_read = - read_register(counter, - NITIO_Gi_SW_Save_Reg(counter->counter_index)); - second_read = - read_register(counter, - NITIO_Gi_SW_Save_Reg(counter->counter_index)); + first_read = read_register(counter, NITIO_SW_SAVE_REG(cidx)); + second_read = read_register(counter, NITIO_SW_SAVE_REG(cidx)); if (first_read != second_read) correct_read = - read_register(counter, - NITIO_Gi_SW_Save_Reg(counter-> - counter_index)); + read_register(counter, NITIO_SW_SAVE_REG(cidx)); else correct_read = first_read; data[0] = correct_read; return 0; break; case 1: - data[0] = - counter_dev-> - regs[NITIO_Gi_LoadA_Reg(counter->counter_index)]; + data[0] = counter_dev->regs[NITIO_LOADA_REG(cidx)]; break; case 2: - data[0] = - counter_dev-> - regs[NITIO_Gi_LoadB_Reg(counter->counter_index)]; + data[0] = counter_dev->regs[NITIO_LOADB_REG(cidx)]; break; } return 0; } -EXPORT_SYMBOL_GPL(ni_tio_rinsn); +EXPORT_SYMBOL_GPL(ni_tio_insn_read); static unsigned ni_tio_next_load_register(struct ni_gpct *counter) { - const unsigned bits = read_register(counter, - NITIO_Gxx_Status_Reg(counter-> - counter_index)); + unsigned cidx = counter->counter_index; + const unsigned bits = + read_register(counter, NITIO_SHARED_STATUS_REG(cidx)); - if (bits & Gi_Next_Load_Source_Bit(counter->counter_index)) - return NITIO_Gi_LoadB_Reg(counter->counter_index); + if (bits & Gi_Next_Load_Source_Bit(cidx)) + return NITIO_LOADB_REG(cidx); else - return NITIO_Gi_LoadA_Reg(counter->counter_index); + return NITIO_LOADA_REG(cidx); } -int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn, - unsigned int *data) +int ni_tio_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct ni_gpct *counter = s->private; struct ni_gpct_device *counter_dev = counter->counter_dev; const unsigned channel = CR_CHAN(insn->chanspec); + unsigned cidx = counter->counter_index; unsigned load_reg; if (insn->n < 1) @@ -1706,24 +1661,18 @@ int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn, /* Don't disturb load source select, just use whichever load register is already selected. */ load_reg = ni_tio_next_load_register(counter); write_register(counter, data[0], load_reg); - ni_tio_set_bits_transient(counter, - NITIO_Gi_Command_Reg(counter-> - counter_index), + ni_tio_set_bits_transient(counter, NITIO_CMD_REG(cidx), 0, 0, Gi_Load_Bit); /* restore state of load reg to whatever the user set last set it to */ write_register(counter, counter_dev->regs[load_reg], load_reg); break; case 1: - counter_dev->regs[NITIO_Gi_LoadA_Reg(counter->counter_index)] = - data[0]; - write_register(counter, data[0], - NITIO_Gi_LoadA_Reg(counter->counter_index)); + counter_dev->regs[NITIO_LOADA_REG(cidx)] = data[0]; + write_register(counter, data[0], NITIO_LOADA_REG(cidx)); break; case 2: - counter_dev->regs[NITIO_Gi_LoadB_Reg(counter->counter_index)] = - data[0]; - write_register(counter, data[0], - NITIO_Gi_LoadB_Reg(counter->counter_index)); + counter_dev->regs[NITIO_LOADB_REG(cidx)] = data[0]; + write_register(counter, data[0], NITIO_LOADB_REG(cidx)); break; default: return -EINVAL; @@ -1731,4 +1680,19 @@ int ni_tio_winsn(struct ni_gpct *counter, struct comedi_insn *insn, } return 0; } -EXPORT_SYMBOL_GPL(ni_tio_winsn); +EXPORT_SYMBOL_GPL(ni_tio_insn_write); + +static int __init ni_tio_init_module(void) +{ + return 0; +} +module_init(ni_tio_init_module); + +static void __exit ni_tio_cleanup_module(void) +{ +} +module_exit(ni_tio_cleanup_module); + +MODULE_AUTHOR("Comedi <comedi@comedi.org>"); +MODULE_DESCRIPTION("Comedi support for NI general-purpose counters"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_tio.h b/drivers/staging/comedi/drivers/ni_tio.h index b0588202e5a..1056bf001e5 100644 --- a/drivers/staging/comedi/drivers/ni_tio.h +++ b/drivers/staging/comedi/drivers/ni_tio.h @@ -13,11 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDI_NI_TIO_H @@ -30,77 +25,77 @@ struct mite_struct; struct ni_gpct_device; enum ni_gpct_register { - NITIO_G0_Autoincrement_Reg, - NITIO_G1_Autoincrement_Reg, - NITIO_G2_Autoincrement_Reg, - NITIO_G3_Autoincrement_Reg, - NITIO_G0_Command_Reg, - NITIO_G1_Command_Reg, - NITIO_G2_Command_Reg, - NITIO_G3_Command_Reg, - NITIO_G0_HW_Save_Reg, - NITIO_G1_HW_Save_Reg, - NITIO_G2_HW_Save_Reg, - NITIO_G3_HW_Save_Reg, - NITIO_G0_SW_Save_Reg, - NITIO_G1_SW_Save_Reg, - NITIO_G2_SW_Save_Reg, - NITIO_G3_SW_Save_Reg, - NITIO_G0_Mode_Reg, - NITIO_G1_Mode_Reg, - NITIO_G2_Mode_Reg, - NITIO_G3_Mode_Reg, - NITIO_G0_LoadA_Reg, - NITIO_G1_LoadA_Reg, - NITIO_G2_LoadA_Reg, - NITIO_G3_LoadA_Reg, - NITIO_G0_LoadB_Reg, - NITIO_G1_LoadB_Reg, - NITIO_G2_LoadB_Reg, - NITIO_G3_LoadB_Reg, - NITIO_G0_Input_Select_Reg, - NITIO_G1_Input_Select_Reg, - NITIO_G2_Input_Select_Reg, - NITIO_G3_Input_Select_Reg, - NITIO_G0_Counting_Mode_Reg, - NITIO_G1_Counting_Mode_Reg, - NITIO_G2_Counting_Mode_Reg, - NITIO_G3_Counting_Mode_Reg, - NITIO_G0_Second_Gate_Reg, - NITIO_G1_Second_Gate_Reg, - NITIO_G2_Second_Gate_Reg, - NITIO_G3_Second_Gate_Reg, - NITIO_G01_Status_Reg, - NITIO_G23_Status_Reg, - NITIO_G01_Joint_Reset_Reg, - NITIO_G23_Joint_Reset_Reg, - NITIO_G01_Joint_Status1_Reg, - NITIO_G23_Joint_Status1_Reg, - NITIO_G01_Joint_Status2_Reg, - NITIO_G23_Joint_Status2_Reg, - NITIO_G0_DMA_Config_Reg, - NITIO_G1_DMA_Config_Reg, - NITIO_G2_DMA_Config_Reg, - NITIO_G3_DMA_Config_Reg, - NITIO_G0_DMA_Status_Reg, - NITIO_G1_DMA_Status_Reg, - NITIO_G2_DMA_Status_Reg, - NITIO_G3_DMA_Status_Reg, - NITIO_G0_ABZ_Reg, - NITIO_G1_ABZ_Reg, - NITIO_G0_Interrupt_Acknowledge_Reg, - NITIO_G1_Interrupt_Acknowledge_Reg, - NITIO_G2_Interrupt_Acknowledge_Reg, - NITIO_G3_Interrupt_Acknowledge_Reg, - NITIO_G0_Status_Reg, - NITIO_G1_Status_Reg, - NITIO_G2_Status_Reg, - NITIO_G3_Status_Reg, - NITIO_G0_Interrupt_Enable_Reg, - NITIO_G1_Interrupt_Enable_Reg, - NITIO_G2_Interrupt_Enable_Reg, - NITIO_G3_Interrupt_Enable_Reg, - NITIO_Num_Registers, + NITIO_G0_AUTO_INC, + NITIO_G1_AUTO_INC, + NITIO_G2_AUTO_INC, + NITIO_G3_AUTO_INC, + NITIO_G0_CMD, + NITIO_G1_CMD, + NITIO_G2_CMD, + NITIO_G3_CMD, + NITIO_G0_HW_SAVE, + NITIO_G1_HW_SAVE, + NITIO_G2_HW_SAVE, + NITIO_G3_HW_SAVE, + NITIO_G0_SW_SAVE, + NITIO_G1_SW_SAVE, + NITIO_G2_SW_SAVE, + NITIO_G3_SW_SAVE, + NITIO_G0_MODE, + NITIO_G1_MODE, + NITIO_G2_MODE, + NITIO_G3_MODE, + NITIO_G0_LOADA, + NITIO_G1_LOADA, + NITIO_G2_LOADA, + NITIO_G3_LOADA, + NITIO_G0_LOADB, + NITIO_G1_LOADB, + NITIO_G2_LOADB, + NITIO_G3_LOADB, + NITIO_G0_INPUT_SEL, + NITIO_G1_INPUT_SEL, + NITIO_G2_INPUT_SEL, + NITIO_G3_INPUT_SEL, + NITIO_G0_CNT_MODE, + NITIO_G1_CNT_MODE, + NITIO_G2_CNT_MODE, + NITIO_G3_CNT_MODE, + NITIO_G0_GATE2, + NITIO_G1_GATE2, + NITIO_G2_GATE2, + NITIO_G3_GATE2, + NITIO_G01_STATUS, + NITIO_G23_STATUS, + NITIO_G01_RESET, + NITIO_G23_RESET, + NITIO_G01_STATUS1, + NITIO_G23_STATUS1, + NITIO_G01_STATUS2, + NITIO_G23_STATUS2, + NITIO_G0_DMA_CFG, + NITIO_G1_DMA_CFG, + NITIO_G2_DMA_CFG, + NITIO_G3_DMA_CFG, + NITIO_G0_DMA_STATUS, + NITIO_G1_DMA_STATUS, + NITIO_G2_DMA_STATUS, + NITIO_G3_DMA_STATUS, + NITIO_G0_ABZ, + NITIO_G1_ABZ, + NITIO_G0_INT_ACK, + NITIO_G1_INT_ACK, + NITIO_G2_INT_ACK, + NITIO_G3_INT_ACK, + NITIO_G0_STATUS, + NITIO_G1_STATUS, + NITIO_G2_STATUS, + NITIO_G3_STATUS, + NITIO_G0_INT_ENA, + NITIO_G1_INT_ENA, + NITIO_G2_INT_ENA, + NITIO_G3_INT_ENA, + NITIO_NUM_REGS, }; enum ni_gpct_variant { @@ -120,55 +115,42 @@ struct ni_gpct { struct ni_gpct_device { struct comedi_device *dev; - void (*write_register) (struct ni_gpct * counter, unsigned bits, - enum ni_gpct_register reg); - unsigned (*read_register) (struct ni_gpct * counter, - enum ni_gpct_register reg); + void (*write_register)(struct ni_gpct *counter, unsigned bits, + enum ni_gpct_register reg); + unsigned (*read_register)(struct ni_gpct *counter, + enum ni_gpct_register reg); enum ni_gpct_variant variant; struct ni_gpct *counters; unsigned num_counters; - unsigned regs[NITIO_Num_Registers]; + unsigned regs[NITIO_NUM_REGS]; spinlock_t regs_lock; }; -extern struct ni_gpct_device *ni_gpct_device_construct(struct comedi_device - *dev, - void (*write_register) - (struct ni_gpct * - counter, unsigned bits, - enum ni_gpct_register - reg), - unsigned (*read_register) - (struct ni_gpct * - counter, - enum ni_gpct_register - reg), - enum ni_gpct_variant - variant, - unsigned num_counters); -extern void ni_gpct_device_destroy(struct ni_gpct_device *counter_dev); -extern void ni_tio_init_counter(struct ni_gpct *counter); -extern int ni_tio_rinsn(struct ni_gpct *counter, - struct comedi_insn *insn, unsigned int *data); -extern int ni_tio_insn_config(struct ni_gpct *counter, - struct comedi_insn *insn, unsigned int *data); -extern int ni_tio_winsn(struct ni_gpct *counter, - struct comedi_insn *insn, unsigned int *data); -extern int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async); -extern int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd); -extern int ni_tio_cancel(struct ni_gpct *counter); -extern void ni_tio_handle_interrupt(struct ni_gpct *counter, - struct comedi_subdevice *s); -extern void ni_tio_set_mite_channel(struct ni_gpct *counter, - struct mite_channel *mite_chan); -extern void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, - int *gate_error, int *tc_error, - int *perm_stale_data, - int *stale_data); - -static inline struct ni_gpct *subdev_to_counter(struct comedi_subdevice *s) -{ - return s->private; -} +struct ni_gpct_device * +ni_gpct_device_construct(struct comedi_device *, + void (*write_register)(struct ni_gpct *, + unsigned bits, + enum ni_gpct_register), + unsigned (*read_register)(struct ni_gpct *, + enum ni_gpct_register), + enum ni_gpct_variant, + unsigned num_counters); +void ni_gpct_device_destroy(struct ni_gpct_device *); +void ni_tio_init_counter(struct ni_gpct *); +int ni_tio_insn_read(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *data); +int ni_tio_insn_config(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *data); +int ni_tio_insn_write(struct comedi_device *, struct comedi_subdevice *, + struct comedi_insn *, unsigned int *data); +int ni_tio_cmd(struct comedi_device *, struct comedi_subdevice *); +int ni_tio_cmdtest(struct comedi_device *, struct comedi_subdevice *, + struct comedi_cmd *); +int ni_tio_cancel(struct ni_gpct *); +void ni_tio_handle_interrupt(struct ni_gpct *, struct comedi_subdevice *); +void ni_tio_set_mite_channel(struct ni_gpct *, struct mite_channel *); +void ni_tio_acknowledge_and_confirm(struct ni_gpct *, + int *gate_error, int *tc_error, + int *perm_stale_data, int *stale_data); #endif /* _COMEDI_NI_TIO_H */ diff --git a/drivers/staging/comedi/drivers/ni_tio_internal.h b/drivers/staging/comedi/drivers/ni_tio_internal.h index c4ca5378583..15b81b8fc5c 100644 --- a/drivers/staging/comedi/drivers/ni_tio_internal.h +++ b/drivers/staging/comedi/drivers/ni_tio_internal.h @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _COMEDI_NI_TIO_INTERNAL_H @@ -26,409 +21,26 @@ #include "ni_tio.h" -static inline enum ni_gpct_register NITIO_Gi_Autoincrement_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Autoincrement_Reg; - break; - case 1: - return NITIO_G1_Autoincrement_Reg; - break; - case 2: - return NITIO_G2_Autoincrement_Reg; - break; - case 3: - return NITIO_G3_Autoincrement_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Command_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Command_Reg; - break; - case 1: - return NITIO_G1_Command_Reg; - break; - case 2: - return NITIO_G2_Command_Reg; - break; - case 3: - return NITIO_G3_Command_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Counting_Mode_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Counting_Mode_Reg; - break; - case 1: - return NITIO_G1_Counting_Mode_Reg; - break; - case 2: - return NITIO_G2_Counting_Mode_Reg; - break; - case 3: - return NITIO_G3_Counting_Mode_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Input_Select_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Input_Select_Reg; - break; - case 1: - return NITIO_G1_Input_Select_Reg; - break; - case 2: - return NITIO_G2_Input_Select_Reg; - break; - case 3: - return NITIO_G3_Input_Select_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gxx_Joint_Reset_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - case 1: - return NITIO_G01_Joint_Reset_Reg; - break; - case 2: - case 3: - return NITIO_G23_Joint_Reset_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gxx_Joint_Status1_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - case 1: - return NITIO_G01_Joint_Status1_Reg; - break; - case 2: - case 3: - return NITIO_G23_Joint_Status1_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gxx_Joint_Status2_Reg(unsigned - counter_index) -{ - switch (counter_index) { - case 0: - case 1: - return NITIO_G01_Joint_Status2_Reg; - break; - case 2: - case 3: - return NITIO_G23_Joint_Status2_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gxx_Status_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - case 1: - return NITIO_G01_Status_Reg; - break; - case 2: - case 3: - return NITIO_G23_Status_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_LoadA_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_LoadA_Reg; - break; - case 1: - return NITIO_G1_LoadA_Reg; - break; - case 2: - return NITIO_G2_LoadA_Reg; - break; - case 3: - return NITIO_G3_LoadA_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_LoadB_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_LoadB_Reg; - break; - case 1: - return NITIO_G1_LoadB_Reg; - break; - case 2: - return NITIO_G2_LoadB_Reg; - break; - case 3: - return NITIO_G3_LoadB_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Mode_Reg(unsigned counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Mode_Reg; - break; - case 1: - return NITIO_G1_Mode_Reg; - break; - case 2: - return NITIO_G2_Mode_Reg; - break; - case 3: - return NITIO_G3_Mode_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_SW_Save_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_SW_Save_Reg; - break; - case 1: - return NITIO_G1_SW_Save_Reg; - break; - case 2: - return NITIO_G2_SW_Save_Reg; - break; - case 3: - return NITIO_G3_SW_Save_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Second_Gate_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Second_Gate_Reg; - break; - case 1: - return NITIO_G1_Second_Gate_Reg; - break; - case 2: - return NITIO_G2_Second_Gate_Reg; - break; - case 3: - return NITIO_G3_Second_Gate_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_DMA_Config_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_DMA_Config_Reg; - break; - case 1: - return NITIO_G1_DMA_Config_Reg; - break; - case 2: - return NITIO_G2_DMA_Config_Reg; - break; - case 3: - return NITIO_G3_DMA_Config_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_DMA_Status_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_DMA_Status_Reg; - break; - case 1: - return NITIO_G1_DMA_Status_Reg; - break; - case 2: - return NITIO_G2_DMA_Status_Reg; - break; - case 3: - return NITIO_G3_DMA_Status_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_ABZ_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_ABZ_Reg; - break; - case 1: - return NITIO_G1_ABZ_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Interrupt_Acknowledge_Reg(int - counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Interrupt_Acknowledge_Reg; - break; - case 1: - return NITIO_G1_Interrupt_Acknowledge_Reg; - break; - case 2: - return NITIO_G2_Interrupt_Acknowledge_Reg; - break; - case 3: - return NITIO_G3_Interrupt_Acknowledge_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Status_Reg(int counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Status_Reg; - break; - case 1: - return NITIO_G1_Status_Reg; - break; - case 2: - return NITIO_G2_Status_Reg; - break; - case 3: - return NITIO_G3_Status_Reg; - break; - default: - BUG(); - break; - } - return 0; -} - -static inline enum ni_gpct_register NITIO_Gi_Interrupt_Enable_Reg(int - counter_index) -{ - switch (counter_index) { - case 0: - return NITIO_G0_Interrupt_Enable_Reg; - break; - case 1: - return NITIO_G1_Interrupt_Enable_Reg; - break; - case 2: - return NITIO_G2_Interrupt_Enable_Reg; - break; - case 3: - return NITIO_G3_Interrupt_Enable_Reg; - break; - default: - BUG(); - break; - } - return 0; -} +#define NITIO_AUTO_INC_REG(x) (NITIO_G0_AUTO_INC + (x)) +#define NITIO_CMD_REG(x) (NITIO_G0_CMD + (x)) +#define NITIO_HW_SAVE_REG(x) (NITIO_G0_HW_SAVE + (x)) +#define NITIO_SW_SAVE_REG(x) (NITIO_G0_SW_SAVE + (x)) +#define NITIO_MODE_REG(x) (NITIO_G0_MODE + (x)) +#define NITIO_LOADA_REG(x) (NITIO_G0_LOADA + (x)) +#define NITIO_LOADB_REG(x) (NITIO_G0_LOADB + (x)) +#define NITIO_INPUT_SEL_REG(x) (NITIO_G0_INPUT_SEL + (x)) +#define NITIO_CNT_MODE_REG(x) (NITIO_G0_CNT_MODE + (x)) +#define NITIO_GATE2_REG(x) (NITIO_G0_GATE2 + (x)) +#define NITIO_SHARED_STATUS_REG(x) (NITIO_G01_STATUS + ((x) / 2)) +#define NITIO_RESET_REG(x) (NITIO_G01_RESET + ((x) / 2)) +#define NITIO_STATUS1_REG(x) (NITIO_G01_STATUS1 + ((x) / 2)) +#define NITIO_STATUS2_REG(x) (NITIO_G01_STATUS2 + ((x) / 2)) +#define NITIO_DMA_CFG_REG(x) (NITIO_G0_DMA_CFG + (x)) +#define NITIO_DMA_STATUS_REG(x) (NITIO_G0_DMA_STATUS + (x)) +#define NITIO_ABZ_REG(x) (NITIO_G0_ABZ + (x)) +#define NITIO_INT_ACK_REG(x) (NITIO_G0_INT_ACK + (x)) +#define NITIO_STATUS_REG(x) (NITIO_G0_STATUS + (x)) +#define NITIO_INT_ENA_REG(x) (NITIO_G0_INT_ENA + (x)) enum Gi_Auto_Increment_Reg_Bits { Gi_Auto_Increment_Mask = 0xff @@ -472,15 +84,22 @@ enum Gi_Counting_Mode_Reg_Bits { Gi_Index_Phase_LowA_HighB = 0x1 << Gi_Index_Phase_Bitshift, Gi_Index_Phase_HighA_LowB = 0x2 << Gi_Index_Phase_Bitshift, Gi_Index_Phase_HighA_HighB = 0x3 << Gi_Index_Phase_Bitshift, - Gi_HW_Arm_Enable_Bit = 0x80, /* from m-series example code, not documented in 660x register level manual */ - Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift, /* from m-series example code, not documented in 660x register level manual */ + /* from m-series example code, not documented in 660x register level + * manual */ + Gi_HW_Arm_Enable_Bit = 0x80, + /* from m-series example code, not documented in 660x register level + * manual */ + Gi_660x_HW_Arm_Select_Mask = 0x7 << Gi_HW_Arm_Select_Shift, Gi_660x_Prescale_X8_Bit = 0x1000, Gi_M_Series_Prescale_X8_Bit = 0x2000, Gi_M_Series_HW_Arm_Select_Mask = 0x1f << Gi_HW_Arm_Select_Shift, - /* must be set for clocks over 40MHz, which includes synchronous counting and quadrature modes */ + /* must be set for clocks over 40MHz, which includes synchronous + * counting and quadrature modes */ Gi_660x_Alternate_Sync_Bit = 0x2000, Gi_M_Series_Alternate_Sync_Bit = 0x4000, - Gi_660x_Prescale_X2_Bit = 0x4000, /* from m-series example code, not documented in 660x register level manual */ + /* from m-series example code, not documented in 660x register level + * manual */ + Gi_660x_Prescale_X2_Bit = 0x4000, Gi_M_Series_Prescale_X2_Bit = 0x8000, }; @@ -503,7 +122,8 @@ enum Gi_Mode_Bits { Gi_Level_Gating_Bits = 0x1, Gi_Rising_Edge_Gating_Bits = 0x2, Gi_Falling_Edge_Gating_Bits = 0x3, - Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with rising edge gating mode */ + Gi_Gate_On_Both_Edges_Bit = 0x4, /* used in conjunction with + * rising edge gating mode */ Gi_Trigger_Mode_for_Edge_Gate_Mask = 0x18, Gi_Edge_Gate_Starts_Stops_Bits = 0x0, Gi_Edge_Gate_Stops_Starts_Bits = 0x8, @@ -686,25 +306,24 @@ static inline unsigned Gi_Gate_Interrupt_Enable_Bit(unsigned counter_index) { unsigned bit; - if (counter_index % 2) { + if (counter_index % 2) bit = G1_Gate_Interrupt_Enable_Bit; - } else { + else bit = G0_Gate_Interrupt_Enable_Bit; - } return bit; } static inline void write_register(struct ni_gpct *counter, unsigned bits, enum ni_gpct_register reg) { - BUG_ON(reg >= NITIO_Num_Registers); + BUG_ON(reg >= NITIO_NUM_REGS); counter->counter_dev->write_register(counter, bits, reg); } static inline unsigned read_register(struct ni_gpct *counter, enum ni_gpct_register reg) { - BUG_ON(reg >= NITIO_Num_Registers); + BUG_ON(reg >= NITIO_NUM_REGS); return counter->counter_dev->read_register(counter, reg); } @@ -736,7 +355,7 @@ static inline void ni_tio_set_bits_transient(struct ni_gpct *counter, struct ni_gpct_device *counter_dev = counter->counter_dev; unsigned long flags; - BUG_ON(register_index >= NITIO_Num_Registers); + BUG_ON(register_index >= NITIO_NUM_REGS); spin_lock_irqsave(&counter_dev->regs_lock, flags); counter_dev->regs[register_index] &= ~bit_mask; counter_dev->regs[register_index] |= (bit_values & bit_mask); @@ -748,8 +367,9 @@ static inline void ni_tio_set_bits_transient(struct ni_gpct *counter, } /* ni_tio_set_bits( ) is for safely writing to registers whose bits may be -twiddled in interrupt context, or whose software copy may be read in interrupt context. -*/ + * twiddled in interrupt context, or whose software copy may be read in + * interrupt context. + */ static inline void ni_tio_set_bits(struct ni_gpct *counter, enum ni_gpct_register register_index, unsigned bit_mask, unsigned bit_values) @@ -770,7 +390,7 @@ static inline unsigned ni_tio_get_soft_copy(const struct ni_gpct *counter, unsigned long flags; unsigned value; - BUG_ON(register_index >= NITIO_Num_Registers); + BUG_ON(register_index >= NITIO_NUM_REGS); spin_lock_irqsave(&counter_dev->regs_lock, flags); value = counter_dev->regs[register_index]; spin_unlock_irqrestore(&counter_dev->regs_lock, flags); diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index a9611587460..2557ab48cb6 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -13,10 +13,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -48,17 +44,16 @@ TODO: Support use of both banks X and Y */ +#include <linux/module.h> +#include "comedi_fc.h" #include "ni_tio_internal.h" #include "mite.h" -MODULE_AUTHOR("Comedi <comedi@comedi.org>"); -MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters"); -MODULE_LICENSE("GPL"); - static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, short read_not_write) { struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; unsigned input_select_bits = 0; if (enable) { @@ -67,8 +62,7 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, else input_select_bits |= Gi_Write_Acknowledges_Irq; } - ni_tio_set_bits(counter, - NITIO_Gi_Input_Select_Reg(counter->counter_index), + ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), Gi_Read_Acknowledges_Irq | Gi_Write_Acknowledges_Irq, input_select_bits); switch (counter_dev->variant) { @@ -85,9 +79,7 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, } if (read_not_write == 0) gi_dma_config_bits |= Gi_DMA_Write_Bit; - ni_tio_set_bits(counter, - NITIO_Gi_DMA_Config_Reg(counter-> - counter_index), + ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), Gi_DMA_Enable_Bit | Gi_DMA_Int_Bit | Gi_DMA_Write_Bit, gi_dma_config_bits); } @@ -97,14 +89,16 @@ static void ni_tio_configure_dma(struct ni_gpct *counter, short enable, static int ni_tio_input_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { + struct ni_gpct *counter = s->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int retval = 0; - struct ni_gpct *counter = s->private; BUG_ON(counter == NULL); - if (trignum != 0) + + if (trig_num != cmd->start_src) return -EINVAL; spin_lock_irqsave(&counter->lock, flags); @@ -121,14 +115,17 @@ static int ni_tio_input_inttrig(struct comedi_device *dev, return retval; } -static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) +static int ni_tio_input_cmd(struct comedi_subdevice *s) { + struct ni_gpct *counter = s->private; struct ni_gpct_device *counter_dev = counter->counter_dev; + unsigned cidx = counter->counter_index; + struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; int retval = 0; /* write alloc the entire buffer */ - comedi_buf_write_alloc(async, async->prealloc_bufsz); + comedi_buf_write_alloc(s, async->prealloc_bufsz); counter->mite_chan->dir = COMEDI_INPUT; switch (counter_dev->variant) { case ni_gpct_variant_m_series: @@ -142,8 +139,7 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) BUG(); break; } - ni_tio_set_bits(counter, NITIO_Gi_Command_Reg(counter->counter_index), - Gi_Save_Trace_Bit, 0); + ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), Gi_Save_Trace_Bit, 0); ni_tio_configure_dma(counter, 1, 1); switch (cmd->start_src) { case TRIG_NOW: @@ -158,6 +154,7 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) async->inttrig = NULL; mite_dma_arm(counter->mite_chan); retval = ni_tio_arm(counter, 1, cmd->start_arg); + break; case TRIG_OTHER: async->inttrig = NULL; mite_dma_arm(counter->mite_chan); @@ -169,10 +166,12 @@ static int ni_tio_input_cmd(struct ni_gpct *counter, struct comedi_async *async) return retval; } -static int ni_tio_output_cmd(struct ni_gpct *counter, - struct comedi_async *async) +static int ni_tio_output_cmd(struct comedi_subdevice *s) { - printk(KERN_ERR "ni_tio: output commands not yet implemented.\n"); + struct ni_gpct *counter = s->private; + + dev_err(counter->counter_dev->dev->class_dev, + "output commands not yet implemented.\n"); return -ENOTSUPP; counter->mite_chan->dir = COMEDI_OUTPUT; @@ -182,9 +181,11 @@ static int ni_tio_output_cmd(struct ni_gpct *counter, return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE); } -static int ni_tio_cmd_setup(struct ni_gpct *counter, struct comedi_async *async) +static int ni_tio_cmd_setup(struct comedi_subdevice *s) { - struct comedi_cmd *cmd = &async->cmd; + struct comedi_cmd *cmd = &s->async->cmd; + struct ni_gpct *counter = s->private; + unsigned cidx = counter->counter_index; int set_gate_source = 0; unsigned gate_source; int retval = 0; @@ -199,34 +200,35 @@ static int ni_tio_cmd_setup(struct ni_gpct *counter, struct comedi_async *async) if (set_gate_source) retval = ni_tio_set_gate_src(counter, 0, gate_source); if (cmd->flags & TRIG_WAKE_EOS) { - ni_tio_set_bits(counter, - NITIO_Gi_Interrupt_Enable_Reg(counter-> - counter_index), - Gi_Gate_Interrupt_Enable_Bit(counter-> - counter_index), - Gi_Gate_Interrupt_Enable_Bit(counter-> - counter_index)); + ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), + Gi_Gate_Interrupt_Enable_Bit(cidx), + Gi_Gate_Interrupt_Enable_Bit(cidx)); } return retval; } -int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async) +int ni_tio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct ni_gpct *counter = s->private; + struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; int retval = 0; unsigned long flags; spin_lock_irqsave(&counter->lock, flags); if (counter->mite_chan == NULL) { - printk(KERN_ERR "ni_tio: commands only supported with DMA. Interrupt-driven commands not yet implemented.\n"); + dev_err(counter->counter_dev->dev->class_dev, + "commands only supported with DMA. "); + dev_err(counter->counter_dev->dev->class_dev, + "Interrupt-driven commands not yet implemented.\n"); retval = -EIO; } else { - retval = ni_tio_cmd_setup(counter, async); + retval = ni_tio_cmd_setup(s); if (retval == 0) { if (cmd->flags & CMDF_WRITE) - retval = ni_tio_output_cmd(counter, async); + retval = ni_tio_output_cmd(s); else - retval = ni_tio_input_cmd(counter, async); + retval = ni_tio_input_cmd(s); } } spin_unlock_irqrestore(&counter->lock, flags); @@ -234,99 +236,66 @@ int ni_tio_cmd(struct ni_gpct *counter, struct comedi_async *async) } EXPORT_SYMBOL_GPL(ni_tio_cmd); -int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd) +int ni_tio_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { + struct ni_gpct *counter = s->private; int err = 0; - int tmp; - int sources; + unsigned int sources; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; sources = TRIG_NOW | TRIG_INT | TRIG_OTHER; if (ni_tio_counting_mode_registers_present(counter->counter_dev)) sources |= TRIG_EXT; - cmd->start_src &= sources; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - sources = TRIG_NOW | TRIG_EXT | TRIG_OTHER; - cmd->convert_src &= sources; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, sources); + + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_NOW | TRIG_EXT | TRIG_OTHER); + 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 2: make sure trigger sources are unique... */ - - if (cmd->start_src != TRIG_NOW && - cmd->start_src != TRIG_INT && - cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_OTHER) - err++; - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_OTHER) - err++; - if (cmd->convert_src != TRIG_OTHER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_NONE) - err++; - /* ... and mutually compatible */ + /* 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); + + /* Step 2b : and mutually compatible */ + if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW) - err++; + err |= -EINVAL; if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ - if (cmd->start_src != TRIG_EXT) { - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - } - if (cmd->scan_begin_src != TRIG_EXT) { - if (cmd->scan_begin_arg) { - cmd->scan_begin_arg = 0; - err++; - } - } - if (cmd->convert_src != TRIG_EXT) { - if (cmd->convert_arg) { - cmd->convert_arg = 0; - err++; - } - } + /* Step 3: check if arguments are trivially valid */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: + case TRIG_OTHER: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + /* start_arg is the start_trigger passed to ni_tio_arm() */ + break; } - if (cmd->stop_src == TRIG_NONE) { - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + if (cmd->scan_begin_src != TRIG_EXT) + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + + if (cmd->convert_src != TRIG_EXT) + 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; @@ -342,6 +311,7 @@ EXPORT_SYMBOL_GPL(ni_tio_cmdtest); int ni_tio_cancel(struct ni_gpct *counter) { + unsigned cidx = counter->counter_index; unsigned long flags; ni_tio_arm(counter, 0, 0); @@ -351,10 +321,8 @@ int ni_tio_cancel(struct ni_gpct *counter) spin_unlock_irqrestore(&counter->lock, flags); ni_tio_configure_dma(counter, 0, 0); - ni_tio_set_bits(counter, - NITIO_Gi_Interrupt_Enable_Reg(counter->counter_index), - Gi_Gate_Interrupt_Enable_Bit(counter->counter_index), - 0x0); + ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx), + Gi_Gate_Interrupt_Enable_Bit(cidx), 0x0); return 0; } EXPORT_SYMBOL_GPL(ni_tio_cancel); @@ -394,14 +362,11 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, int *tc_error, int *perm_stale_data, int *stale_data) { + unsigned cidx = counter->counter_index; const unsigned short gxx_status = read_register(counter, - NITIO_Gxx_Status_Reg - (counter-> - counter_index)); + NITIO_SHARED_STATUS_REG(cidx)); const unsigned short gi_status = read_register(counter, - NITIO_Gi_Status_Reg - (counter-> - counter_index)); + NITIO_STATUS_REG(cidx)); unsigned ack = 0; if (gate_error) @@ -413,8 +378,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, if (stale_data) *stale_data = 0; - if (gxx_status & Gi_Gate_Error_Bit(counter->counter_index)) { - ack |= Gi_Gate_Error_Confirm_Bit(counter->counter_index); + if (gxx_status & Gi_Gate_Error_Bit(cidx)) { + ack |= Gi_Gate_Error_Confirm_Bit(cidx); if (gate_error) { /*660x don't support automatic acknowledgement of gate interrupt via dma read/write @@ -425,8 +390,8 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, } } } - if (gxx_status & Gi_TC_Error_Bit(counter->counter_index)) { - ack |= Gi_TC_Error_Confirm_Bit(counter->counter_index); + if (gxx_status & Gi_TC_Error_Bit(cidx)) { + ack |= Gi_TC_Error_Confirm_Bit(cidx); if (tc_error) *tc_error = 1; } @@ -437,23 +402,18 @@ void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter, int *gate_error, ack |= Gi_Gate_Interrupt_Ack_Bit; } if (ack) - write_register(counter, ack, - NITIO_Gi_Interrupt_Acknowledge_Reg - (counter->counter_index)); - if (ni_tio_get_soft_copy - (counter, - NITIO_Gi_Mode_Reg(counter->counter_index)) & + write_register(counter, ack, NITIO_INT_ACK_REG(cidx)); + if (ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx)) & Gi_Loading_On_Gate_Bit) { - if (gxx_status & Gi_Stale_Data_Bit(counter->counter_index)) { + if (gxx_status & Gi_Stale_Data_Bit(cidx)) { if (stale_data) *stale_data = 1; } - if (read_register(counter, - NITIO_Gxx_Joint_Status2_Reg - (counter->counter_index)) & - Gi_Permanent_Stale_Bit(counter->counter_index)) { - printk(KERN_INFO "%s: Gi_Permanent_Stale_Data detected.\n", - __func__); + if (read_register(counter, NITIO_STATUS2_REG(cidx)) & + Gi_Permanent_Stale_Bit(cidx)) { + dev_info(counter->counter_dev->dev->class_dev, + "%s: Gi_Permanent_Stale_Data detected.\n", + __func__); if (perm_stale_data) *perm_stale_data = 1; } @@ -464,6 +424,7 @@ EXPORT_SYMBOL_GPL(ni_tio_acknowledge_and_confirm); void ni_tio_handle_interrupt(struct ni_gpct *counter, struct comedi_subdevice *s) { + unsigned cidx = counter->counter_index; unsigned gpct_mite_status; unsigned long flags; int gate_error; @@ -473,7 +434,8 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error, &perm_stale_data, NULL); if (gate_error) { - printk(KERN_NOTICE "%s: Gi_Gate_Error detected.\n", __func__); + dev_notice(counter->counter_dev->dev->class_dev, + "%s: Gi_Gate_Error detected.\n", __func__); s->async->events |= COMEDI_CB_OVERFLOW; } if (perm_stale_data) @@ -481,11 +443,10 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, switch (counter->counter_dev->variant) { case ni_gpct_variant_m_series: case ni_gpct_variant_660x: - if (read_register(counter, - NITIO_Gi_DMA_Status_Reg - (counter->counter_index)) & Gi_DRQ_Error_Bit) { - printk(KERN_NOTICE "%s: Gi_DRQ_Error detected.\n", - __func__); + if (read_register(counter, NITIO_DMA_STATUS_REG(cidx)) & + Gi_DRQ_Error_Bit) { + dev_notice(counter->counter_dev->dev->class_dev, + "%s: Gi_DRQ_Error detected.\n", __func__); s->async->events |= COMEDI_CB_OVERFLOW; } break; @@ -503,7 +464,7 @@ void ni_tio_handle_interrupt(struct ni_gpct *counter, counter->mite_chan->mite->mite_io_addr + MITE_CHOR(counter->mite_chan->channel)); } - mite_sync_input_dma(counter->mite_chan, s->async); + mite_sync_input_dma(counter->mite_chan, s); spin_unlock_irqrestore(&counter->lock, flags); } EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt); @@ -523,11 +484,13 @@ static int __init ni_tiocmd_init_module(void) { return 0; } - module_init(ni_tiocmd_init_module); static void __exit ni_tiocmd_cleanup_module(void) { } - module_exit(ni_tiocmd_cleanup_module); + +MODULE_AUTHOR("Comedi <comedi@comedi.org>"); +MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index b44386a6b63..c38d97a9a89 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -1,147 +1,127 @@ /* - comedi/drivers/pcl711.c - hardware driver for PC-LabCard PCL-711 and AdSys ACL-8112 - and compatibles - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - Janne Jalkanen <jalkanen@cs.hut.fi> - Eric Bunn <ebu@cs.hut.fi> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - + * pcl711.c + * Comedi driver for PC-LabCard PCL-711 and AdSys ACL-8112 and compatibles + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * Janne Jalkanen <jalkanen@cs.hut.fi> + * Eric Bunn <ebu@cs.hut.fi> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -/* -Driver: pcl711 -Description: Advantech PCL-711 and 711b, ADLink ACL-8112 -Author: ds, Janne Jalkanen <jalkanen@cs.hut.fi>, Eric Bunn <ebu@cs.hut.fi> -Status: mostly complete -Devices: [Advantech] PCL-711 (pcl711), PCL-711B (pcl711b), - [AdLink] ACL-8112HG (acl8112hg), ACL-8112DG (acl8112dg) - -Since these boards do not have DMA or FIFOs, only immediate mode is -supported. - -*/ /* - Dave Andruczyk <dave@tech.buffalostate.edu> also wrote a - driver for the PCL-711. I used a few ideas from his driver - here. His driver also has more comments, if you are - interested in understanding how this driver works. - http://tech.buffalostate.edu/~dave/driver/ - - The ACL-8112 driver was hacked from the sources of the PCL-711 - driver (the 744 chip used on the 8112 is almost the same as - the 711b chip, but it has more I/O channels) by - Janne Jalkanen (jalkanen@cs.hut.fi) and - Erik Bunn (ebu@cs.hut.fi). Remerged with the PCL-711 driver - by ds. - - [acl-8112] - This driver supports both TRIGNOW and TRIGCLK, - but does not yet support DMA transfers. It also supports - both high (HG) and low (DG) versions of the card, though - the HG version has been untested. - + * Driver: pcl711 + * Description: Advantech PCL-711 and 711b, ADLink ACL-8112 + * Devices: (Advantech) PCL-711 [pcl711] + * (Advantech) PCL-711B [pcl711b] + * (AdLink) ACL-8112HG [acl8112hg] + * (AdLink) ACL-8112DG [acl8112dg] + * Author: David A. Schleef <ds@schleef.org> + * Janne Jalkanen <jalkanen@cs.hut.fi> + * Eric Bunn <ebu@cs.hut.fi> + * Updated: + * Status: mostly complete + * + * Configuration Options: + * [0] - I/O port base + * [1] - IRQ, optional */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> -#include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/delay.h> +#include "../comedidev.h" +#include "comedi_fc.h" #include "8253.h" -#define PCL711_SIZE 16 - -#define PCL711_CTR0 0 -#define PCL711_CTR1 1 -#define PCL711_CTR2 2 -#define PCL711_CTRCTL 3 -#define PCL711_AD_LO 4 -#define PCL711_DA0_LO 4 -#define PCL711_AD_HI 5 -#define PCL711_DA0_HI 5 -#define PCL711_DI_LO 6 -#define PCL711_DA1_LO 6 -#define PCL711_DI_HI 7 -#define PCL711_DA1_HI 7 -#define PCL711_CLRINTR 8 -#define PCL711_GAIN 9 -#define PCL711_MUX 10 -#define PCL711_MODE 11 -#define PCL711_SOFTTRIG 12 -#define PCL711_DO_LO 13 -#define PCL711_DO_HI 14 - -static const struct comedi_lrange range_pcl711b_ai = { 5, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(0.3125) - } +/* + * I/O port register map + */ +#define PCL711_TIMER_BASE 0x00 +#define PCL711_AI_LSB_REG 0x04 +#define PCL711_AI_MSB_REG 0x05 +#define PCL711_AI_MSB_DRDY (1 << 4) +#define PCL711_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL711_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL711_DI_LSB_REG 0x06 +#define PCL711_DI_MSB_REG 0x07 +#define PCL711_INT_STAT_REG 0x08 +#define PCL711_INT_STAT_CLR (0 << 0) /* any value will work */ +#define PCL711_AI_GAIN_REG 0x09 +#define PCL711_AI_GAIN(x) (((x) & 0xf) << 0) +#define PCL711_MUX_REG 0x0a +#define PCL711_MUX_CHAN(x) (((x) & 0xf) << 0) +#define PCL711_MUX_CS0 (1 << 4) +#define PCL711_MUX_CS1 (1 << 5) +#define PCL711_MUX_DIFF (PCL711_MUX_CS0 | PCL711_MUX_CS1) +#define PCL711_MODE_REG 0x0b +#define PCL711_MODE_DEFAULT (0 << 0) +#define PCL711_MODE_SOFTTRIG (1 << 0) +#define PCL711_MODE_EXT (2 << 0) +#define PCL711_MODE_EXT_IRQ (3 << 0) +#define PCL711_MODE_PACER (4 << 0) +#define PCL711_MODE_PACER_IRQ (6 << 0) +#define PCL711_MODE_IRQ(x) (((x) & 0x7) << 4) +#define PCL711_SOFTTRIG_REG 0x0c +#define PCL711_SOFTTRIG (0 << 0) /* any value will work */ +#define PCL711_DO_LSB_REG 0x0d +#define PCL711_DO_MSB_REG 0x0e + +static const struct comedi_lrange range_pcl711b_ai = { + 5, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_acl8112hg_ai = { 12, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01) - } +static const struct comedi_lrange range_acl8112hg_ai = { + 12, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_acl8112dg_ai = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10) - } +static const struct comedi_lrange range_acl8112dg_ai = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; -/* - * flags - */ - -#define PCL711_TIMEOUT 100 -#define PCL711_DRDY 0x10 - -static const int i8253_osc_base = 500; /* 2 Mhz */ - struct pcl711_board { - const char *name; - int is_pcl711b; - int is_8112; - int is_dg; - int n_ranges; int n_aichan; int n_aochan; int maxirq; @@ -149,246 +129,227 @@ struct pcl711_board { }; static const struct pcl711_board boardtypes[] = { - {"pcl711", 0, 0, 0, 5, 8, 1, 0, &range_bipolar5}, - {"pcl711b", 1, 0, 0, 5, 8, 1, 7, &range_pcl711b_ai}, - {"acl8112hg", 0, 1, 0, 12, 16, 2, 15, &range_acl8112hg_ai}, - {"acl8112dg", 0, 1, 1, 9, 16, 2, 15, &range_acl8112dg_ai}, + { + .name = "pcl711", + .n_aichan = 8, + .n_aochan = 1, + .ai_range_type = &range_bipolar5, + }, { + .name = "pcl711b", + .n_aichan = 8, + .n_aochan = 1, + .maxirq = 7, + .ai_range_type = &range_pcl711b_ai, + }, { + .name = "acl8112hg", + .n_aichan = 16, + .n_aochan = 2, + .maxirq = 15, + .ai_range_type = &range_acl8112hg_ai, + }, { + .name = "acl8112dg", + .n_aichan = 16, + .n_aochan = 2, + .maxirq = 15, + .ai_range_type = &range_acl8112dg_ai, + }, }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl711_board)) -#define this_board ((const struct pcl711_board *)dev->board_ptr) - -static int pcl711_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl711_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcl711 = { - .driver_name = "pcl711", - .module = THIS_MODULE, - .attach = pcl711_attach, - .detach = pcl711_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl711_board), +struct pcl711_private { + unsigned int ntrig; + unsigned int ao_readback[2]; + unsigned int divisor1; + unsigned int divisor2; }; -static int __init driver_pcl711_init_module(void) +static void pcl711_ai_set_mode(struct comedi_device *dev, unsigned int mode) { - return comedi_driver_register(&driver_pcl711); -} + /* + * The pcl711b board uses bits in the mode register to select the + * interrupt. The other boards supported by this driver all use + * jumpers on the board. + * + * Enables the interrupt when needed on the pcl711b board. These + * bits do nothing on the other boards. + */ + if (mode == PCL711_MODE_EXT_IRQ || mode == PCL711_MODE_PACER_IRQ) + mode |= PCL711_MODE_IRQ(dev->irq); -static void __exit driver_pcl711_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl711); + outb(mode, dev->iobase + PCL711_MODE_REG); } -module_init(driver_pcl711_init_module); -module_exit(driver_pcl711_cleanup_module); +static unsigned int pcl711_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; -struct pcl711_private { + val = inb(dev->iobase + PCL711_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL711_AI_LSB_REG); - int board; - int adchan; - int ntrig; - int aip[8]; - int mode; - unsigned int ao_readback[2]; - unsigned int divisor1; - unsigned int divisor2; -}; + return val & s->maxdata; +} -#define devpriv ((struct pcl711_private *)dev->private) +static int pcl711_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); + return 0; +} static irqreturn_t pcl711_interrupt(int irq, void *d) { - int lo, hi; - int data; struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct pcl711_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int data; if (!dev->attached) { comedi_error(dev, "spurious interrupt"); return IRQ_HANDLED; } - hi = inb(dev->iobase + PCL711_AD_HI); - lo = inb(dev->iobase + PCL711_AD_LO); - outb(0, dev->iobase + PCL711_CLRINTR); + data = pcl711_ai_get_sample(dev, s); - data = (hi << 8) | lo; + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); - /* FIXME! Nothing else sets ntrig! */ - if (!(--devpriv->ntrig)) { - if (this_board->is_8112) - outb(1, dev->iobase + PCL711_MODE); - else - outb(0, dev->iobase + PCL711_MODE); - - s->async->events |= COMEDI_CB_EOA; + if (comedi_buf_put(s, data) == 0) { + s->async->events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR; + } else { + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; + if (cmd->stop_src == TRIG_COUNT && !(--devpriv->ntrig)) { + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); + s->async->events |= COMEDI_CB_EOA; + } } comedi_event(dev, s); return IRQ_HANDLED; } -static void pcl711_set_changain(struct comedi_device *dev, int chan) +static void pcl711_set_changain(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chanspec) { - int chan_register; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int mux = 0; + + outb(PCL711_AI_GAIN(range), dev->iobase + PCL711_AI_GAIN_REG); + + if (s->n_chan > 8) { + /* Select the correct MPC508A chip */ + if (aref == AREF_DIFF) { + chan &= 0x7; + mux |= PCL711_MUX_DIFF; + } else { + if (chan < 8) + mux |= PCL711_MUX_CS0; + else + mux |= PCL711_MUX_CS1; + } + } + outb(mux | PCL711_MUX_CHAN(chan), dev->iobase + PCL711_MUX_REG); +} - outb(CR_RANGE(chan), dev->iobase + PCL711_GAIN); +static int pcl711_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; - chan_register = CR_CHAN(chan); + status = inb(dev->iobase + PCL711_AI_MSB_REG); + if ((status & PCL711_AI_MSB_DRDY) == 0) + return 0; + return -EBUSY; +} - if (this_board->is_8112) { +static int pcl711_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int ret; + int i; - /* - * Set the correct channel. The two channel banks are switched - * using the mask value. - * NB: To use differential channels, you should use - * mask = 0x30, but I haven't written the support for this - * yet. /JJ - */ + pcl711_set_changain(dev, s, insn->chanspec); - if (chan_register >= 8) - chan_register = 0x20 | (chan_register & 0x7); - else - chan_register |= 0x10; - } else { - outb(chan_register, dev->iobase + PCL711_MUX); - } -} + pcl711_ai_set_mode(dev, PCL711_MODE_SOFTTRIG); -static int pcl711_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i, n; - int hi, lo; - - pcl711_set_changain(dev, insn->chanspec); - - for (n = 0; n < insn->n; n++) { - /* - * Write the correct mode (software polling) and start polling - * by writing to the trigger register - */ - outb(1, dev->iobase + PCL711_MODE); - - if (!this_board->is_8112) - outb(0, dev->iobase + PCL711_SOFTTRIG); - - i = PCL711_TIMEOUT; - while (--i) { - hi = inb(dev->iobase + PCL711_AD_HI); - if (!(hi & PCL711_DRDY)) - goto ok; - udelay(1); - } - printk(KERN_ERR "comedi%d: pcl711: A/D timeout\n", dev->minor); - return -ETIME; + for (i = 0; i < insn->n; i++) { + outb(PCL711_SOFTTRIG, dev->iobase + PCL711_SOFTTRIG_REG); -ok: - lo = inb(dev->iobase + PCL711_AD_LO); + ret = comedi_timeout(dev, s, insn, pcl711_ai_eoc, 0); + if (ret) + return ret; - data[n] = ((hi & 0xf) << 8) | lo; + data[i] = pcl711_ai_get_sample(dev, s); } - return n; + return insn->n; } static int pcl711_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int tmp; + struct pcl711_private *devpriv = dev->private; int err = 0; + unsigned int arg; - /* step 1 */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2 */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3 */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } if (cmd->scan_begin_src == TRIG_EXT) { - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); } else { #define MAX_SPEED 1000 -#define TIMER_BASE 100 - if (cmd->scan_begin_arg < MAX_SPEED) { - cmd->scan_begin_arg = MAX_SPEED; - err++; - } - } - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_NONE) { - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } else { - /* ignore */ + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + MAX_SPEED); } + 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) + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + if (err) return 3; /* step 4 */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &devpriv->divisor1, - &devpriv->divisor2, - &cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (err) @@ -397,249 +358,213 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, return 0; } +static void pcl711_ai_load_counters(struct comedi_device *dev) +{ + struct pcl711_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL711_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + + i8254_write(timer_base, 0, 1, devpriv->divisor1); + i8254_write(timer_base, 0, 2, devpriv->divisor2); +} + static int pcl711_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - int timer1, timer2; + struct pcl711_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - pcl711_set_changain(dev, cmd->chanlist[0]); + 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; + } + devpriv->ntrig = cmd->stop_arg; + } if (cmd->scan_begin_src == TRIG_TIMER) { - /* - * Set timers - * timer chip is an 8253, with timers 1 and 2 - * cascaded - * 0x74 = Select Counter 1 | LSB/MSB | Mode=2 | Binary - * Mode 2 = Rate generator - * - * 0xb4 = Select Counter 2 | LSB/MSB | Mode=2 | Binary - */ - - timer1 = timer2 = 0; - i8253_cascade_ns_to_timer(i8253_osc_base, &timer1, &timer2, - &cmd->scan_begin_arg, - TRIG_ROUND_NEAREST); - - outb(0x74, dev->iobase + PCL711_CTRCTL); - outb(timer1 & 0xff, dev->iobase + PCL711_CTR1); - outb((timer1 >> 8) & 0xff, dev->iobase + PCL711_CTR1); - outb(0xb4, dev->iobase + PCL711_CTRCTL); - outb(timer2 & 0xff, dev->iobase + PCL711_CTR2); - outb((timer2 >> 8) & 0xff, dev->iobase + PCL711_CTR2); - - /* clear pending interrupts (just in case) */ - outb(0, dev->iobase + PCL711_CLRINTR); - - /* - * Set mode to IRQ transfer - */ - outb(devpriv->mode | 6, dev->iobase + PCL711_MODE); + pcl711_ai_load_counters(dev); + outb(PCL711_INT_STAT_CLR, dev->iobase + PCL711_INT_STAT_REG); + pcl711_ai_set_mode(dev, PCL711_MODE_PACER_IRQ); } else { - /* external trigger */ - outb(devpriv->mode | 3, dev->iobase + PCL711_MODE); + pcl711_ai_set_mode(dev, PCL711_MODE_EXT_IRQ); } return 0; } -/* - analog output -*/ -static int pcl711_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl711_ao_write(struct comedi_device *dev, + unsigned int chan, unsigned int val) { - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { - outb((data[n] & 0xff), - dev->iobase + (chan ? PCL711_DA1_LO : PCL711_DA0_LO)); - outb((data[n] >> 8), - dev->iobase + (chan ? PCL711_DA1_HI : PCL711_DA0_HI)); + outb(val & 0xff, dev->iobase + PCL711_AO_LSB_REG(chan)); + outb((val >> 8) & 0xff, dev->iobase + PCL711_AO_MSB_REG(chan)); +} - devpriv->ao_readback[chan] = data[n]; +static int pcl711_ao_insn_write(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); + unsigned int val = devpriv->ao_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 n; + 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 comedi_insn *insn, + unsigned int *data) { - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; + struct pcl711_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - return n; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + return insn->n; } -/* Digital port read - Untested on 8112 */ static int pcl711_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; + unsigned int val; - data[1] = inb(dev->iobase + PCL711_DI_LO) | - (inb(dev->iobase + PCL711_DI_HI) << 8); + val = inb(dev->iobase + PCL711_DI_LSB_REG); + val |= (inb(dev->iobase + PCL711_DI_MSB_REG) << 8); - return 2; + data[1] = val; + + return insn->n; } -/* Digital port write - Untested on 8112 */ static int pcl711_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x00ff) + outb(s->state & 0xff, dev->iobase + PCL711_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), dev->iobase + PCL711_DO_MSB_REG); } - if (data[0] & 0x00ff) - outb(s->state & 0xff, dev->iobase + PCL711_DO_LO); - if (data[0] & 0xff00) - outb((s->state >> 8), dev->iobase + PCL711_DO_HI); data[1] = s->state; - return 2; -} - -/* Free any resources that we have claimed */ -static int pcl711_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pcl711: remove\n", dev->minor); - - if (dev->irq) - free_irq(dev->irq, dev); - - if (dev->iobase) - release_region(dev->iobase, PCL711_SIZE); - - return 0; + return insn->n; } -/* Initialization */ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int ret; - unsigned long iobase; - unsigned int irq; + const struct pcl711_board *board = comedi_board(dev); + struct pcl711_private *devpriv; struct comedi_subdevice *s; + int ret; - /* claim our I/O space */ - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: pcl711: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, PCL711_SIZE, "pcl711")) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - /* there should be a sanity check here */ + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - /* set up some name stuff */ - dev->board_name = this_board->name; + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; - /* grab our IRQ */ - irq = it->options[1]; - if (irq > this_board->maxirq) { - printk(KERN_ERR "irq out of range\n"); - return -EINVAL; + if (it->options[1] && it->options[1] <= board->maxirq) { + ret = request_irq(it->options[1], pcl711_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - if (irq) { - if (request_irq(irq, pcl711_interrupt, 0, "pcl711", dev)) { - printk(KERN_ERR "unable to allocate irq %u\n", irq); - return -EINVAL; - } else { - printk(KERN_INFO "( irq = %u )\n", irq); - } - } - dev->irq = irq; - - ret = alloc_subdevices(dev, 4); - if (ret < 0) - return ret; - ret = alloc_private(dev, sizeof(struct pcl711_private)); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - s = dev->subdevices + 0; - /* AI subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = this_board->n_aichan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->range_table = this_board->ai_range_type; - s->insn_read = pcl711_ai_insn; - if (irq) { + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + if (board->n_aichan > 8) + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan; + s->maxdata = 0xfff; + s->range_table = board->ai_range_type; + s->insn_read = pcl711_ai_insn_read; + if (dev->irq) { dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmdtest = pcl711_ai_cmdtest; - s->do_cmd = pcl711_ai_cmd; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = 1; + s->do_cmdtest = pcl711_ai_cmdtest; + s->do_cmd = pcl711_ai_cmd; + s->cancel = pcl711_ai_cancel; } - s++; - /* AO subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = this_board->n_aochan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->range_table = &range_bipolar5; - s->insn_write = pcl711_ao_insn; - s->insn_read = pcl711_ao_insn_read; - - s++; - /* 16-bit digital input */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 16; - s->range_table = &range_digital; - s->insn_bits = pcl711_di_insn_bits; - - s++; - /* 16-bit digital out */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 16; - s->range_table = &range_digital; - s->state = 0; - s->insn_bits = pcl711_do_insn_bits; - - /* - this is the "base value" for the mode register, which is - used for the irq on the PCL711 - */ - if (this_board->is_pcl711b) - devpriv->mode = (dev->irq << 4); + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_aochan; + s->maxdata = 0xfff; + s->range_table = &range_bipolar5; + s->insn_write = pcl711_ao_insn_write; + s->insn_read = pcl711_ao_insn_read; + + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl711_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl711_do_insn_bits; /* clear DAC */ - outb(0, dev->iobase + PCL711_DA0_LO); - outb(0, dev->iobase + PCL711_DA0_HI); - outb(0, dev->iobase + PCL711_DA1_LO); - outb(0, dev->iobase + PCL711_DA1_HI); - - printk(KERN_INFO "\n"); + pcl711_ao_write(dev, 0, 0x0); + pcl711_ao_write(dev, 1, 0x0); return 0; } +static struct comedi_driver pcl711_driver = { + .driver_name = "pcl711", + .module = THIS_MODULE, + .attach = pcl711_attach, + .detach = comedi_legacy_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl711_board), +}; +module_comedi_driver(pcl711_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for PCL-711 compatible boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c index 61b075db66e..8af13e790ad 100644 --- a/drivers/staging/comedi/drivers/pcl724.c +++ b/drivers/staging/comedi/drivers/pcl724.c @@ -1,124 +1,82 @@ /* - comedi/drivers/pcl724.c - - Michal Dobes <dobes@tesnet.cz> - - hardware driver for Advantech cards: - card: PCL-724, PCL-722, PCL-731 - driver: pcl724, pcl722, pcl731 - and ADLink cards: - card: ACL-7122, ACL-7124, PET-48DIO - driver: acl7122, acl7124, pet48dio - - Options for PCL-724, PCL-731, ACL-7124 and PET-48DIO: - [0] - IO Base - - Options for PCL-722 and ACL-7122: - [0] - IO Base - [1] - IRQ (0=disable IRQ) IRQ isn't supported at this time! - [2] -number of DIO: - 0, 144: 144 DIO configuration - 1, 96: 96 DIO configuration -*/ -/* -Driver: pcl724 -Description: Advantech PCL-724, PCL-722, PCL-731 ADLink ACL-7122, ACL-7124, - PET-48DIO -Author: Michal Dobes <dobes@tesnet.cz> -Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731), - [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio) -Status: untested - -This is driver for digital I/O boards PCL-722/724/731 with 144/24/48 DIO -and for digital I/O boards ACL-7122/7124/PET-48DIO with 144/24/48 DIO. -It need 8255.o for operations and only immediate mode is supported. -See the source for configuration details. -*/ + * pcl724.c + * Comedi driver for 8255 based ISA and PC/104 DIO boards + * + * Michal Dobes <dobes@tesnet.cz> + */ + /* - * check_driver overrides: - * struct comedi_insn + * Driver: pcl724 + * Description: Comedi driver for 8255 based ISA DIO boards + * Devices: (Advantech) PCL-724 [pcl724] + * (Advantech) PCL-722 [pcl722] + * (Advantech) PCL-731 [pcl731] + * (ADLink) ACL-7122 [acl7122] + * (ADLink) ACL-7124 [acl7124] + * (ADLink) PET-48DIO [pet48dio] + * (WinSystems) PCM-IO48 [pcmio48] + * Author: Michal Dobes <dobes@tesnet.cz> + * Status: untested + * + * Configuration options: + * [0] - IO Base + * [1] - IRQ (not supported) + * [2] - number of DIO (pcl722 and acl7122 boards) + * 0, 144: 144 DIO configuration + * 1, 96: 96 DIO configuration */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/delay.h> - #include "8255.h" -#define PCL722_SIZE 32 -#define PCL722_96_SIZE 16 -#define PCL724_SIZE 4 -#define PCL731_SIZE 8 -#define PET48_SIZE 2 - #define SIZE_8255 4 -/* #define PCL724_IRQ 1 no IRQ support now */ - -static int pcl724_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl724_detach(struct comedi_device *dev); - struct pcl724_board { - - const char *name; /* board name */ - int dio; /* num of DIO */ - int numofports; /* num of 8255 subdevices */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int io_range; /* len of IO space */ - char can_have96; - char is_pet48; + const char *name; + unsigned int io_range; + unsigned int can_have96:1; + unsigned int is_pet48:1; + int numofports; }; static const struct pcl724_board boardtypes[] = { - {"pcl724", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,}, - {"pcl722", 144, 6, 0x00fc, PCL722_SIZE, 1, 0,}, - {"pcl731", 48, 2, 0x9cfc, PCL731_SIZE, 0, 0,}, - {"acl7122", 144, 6, 0x9ee8, PCL722_SIZE, 1, 0,}, - {"acl7124", 24, 1, 0x00fc, PCL724_SIZE, 0, 0,}, - {"pet48dio", 48, 2, 0x9eb8, PET48_SIZE, 0, 1,}, + { + .name = "pcl724", + .io_range = 0x04, + .numofports = 1, /* 24 DIO channels */ + }, { + .name = "pcl722", + .io_range = 0x20, + .can_have96 = 1, + .numofports = 6, /* 144 (or 96) DIO channels */ + }, { + .name = "pcl731", + .io_range = 0x08, + .numofports = 2, /* 48 DIO channels */ + }, { + .name = "acl7122", + .io_range = 0x20, + .can_have96 = 1, + .numofports = 6, /* 144 (or 96) DIO channels */ + }, { + .name = "acl7124", + .io_range = 0x04, + .numofports = 1, /* 24 DIO channels */ + }, { + .name = "pet48dio", + .io_range = 0x02, + .is_pet48 = 1, + .numofports = 2, /* 48 DIO channels */ + }, { + .name = "pcmio48", + .io_range = 0x08, + .numofports = 2, /* 48 DIO channels */ + }, }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl724_board)) -#define this_board ((const struct pcl724_board *)dev->board_ptr) - -static struct comedi_driver driver_pcl724 = { - .driver_name = "pcl724", - .module = THIS_MODULE, - .attach = pcl724_attach, - .detach = pcl724_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl724_board), -}; - -static int __init driver_pcl724_init_module(void) -{ - return comedi_driver_register(&driver_pcl724); -} - -static void __exit driver_pcl724_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl724); -} - -module_init(driver_pcl724_init_module); -module_exit(driver_pcl724_cleanup_module); - -static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) -{ - unsigned long iobase = arg; - - if (dir) { - outb(data, iobase + port); - return 0; - } else { - return inb(iobase + port); - } -} - -static int subdev_8255mapped_cb(int dir, int port, int data, +static int pcl724_8255mapped_io(int dir, int port, int data, unsigned long iobase) { int movport = SIZE_8255 * (iobase >> 12); @@ -135,104 +93,63 @@ static int subdev_8255mapped_cb(int dir, int port, int data, } } -static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pcl724_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { + const struct pcl724_board *board = comedi_board(dev); + struct comedi_subdevice *s; unsigned long iobase; unsigned int iorange; - int ret, i, n_subdevices; -#ifdef PCL724_IRQ - unsigned int irq; -#endif - - iobase = it->options[0]; - iorange = this_board->io_range; - if ((this_board->can_have96) && ((it->options[1] == 1) - || (it->options[1] == 96))) - iorange = PCL722_96_SIZE; /* PCL-724 in 96 DIO configuration */ - printk(KERN_INFO "comedi%d: pcl724: board=%s, 0x%03lx ", dev->minor, - this_board->name, iobase); - if (!request_region(iobase, iorange, "pcl724")) { - printk("I/O port conflict\n"); - return -EIO; - } - - dev->iobase = iobase; - - dev->board_name = this_board->name; - -#ifdef PCL724_IRQ - irq = 0; - if (this_board->IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & this_board->IRQbits) == 0) { - printk(KERN_WARNING - ", IRQ %u is out of allowed range, " - "DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq - (irq, interrupt_pcl724, 0, "pcl724", dev)) { - printk(KERN_WARNING - ", unable to allocate IRQ %u, " - "DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(", irq=%u", irq); - } - } - } - } + int n_subdevices; + int ret; + int i; - dev->irq = irq; -#endif + iorange = board->io_range; + n_subdevices = board->numofports; - printk("\n"); + /* Handle PCL-724 in 96 DIO configuration */ + if (board->can_have96 && + (it->options[2] == 1 || it->options[2] == 96)) { + iorange = 0x10; + n_subdevices = 4; + } - n_subdevices = this_board->numofports; - if ((this_board->can_have96) && ((it->options[1] == 1) - || (it->options[1] == 96))) - n_subdevices = 4; /* PCL-724 in 96 DIO configuration */ + ret = comedi_request_region(dev, it->options[0], iorange); + if (ret) + return ret; - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, n_subdevices); + if (ret) return ret; for (i = 0; i < dev->n_subdevices; i++) { - if (this_board->is_pet48) { - subdev_8255_init(dev, dev->subdevices + i, - subdev_8255mapped_cb, - (unsigned long)(dev->iobase + - i * 0x1000)); - } else - subdev_8255_init(dev, dev->subdevices + i, - subdev_8255_cb, - (unsigned long)(dev->iobase + - SIZE_8255 * i)); + s = &dev->subdevices[i]; + if (board->is_pet48) { + iobase = dev->iobase + (i * 0x1000); + 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); + } + if (ret) + return ret; } return 0; } -static int pcl724_detach(struct comedi_device *dev) -{ - int i; - - /* printk("comedi%d: pcl724: remove\n",dev->minor); */ - - for (i = 0; i < dev->n_subdevices; i++) - subdev_8255_cleanup(dev, dev->subdevices + i); - -#ifdef PCL724_IRQ - if (dev->irq) - free_irq(dev->irq, dev); -#endif - - release_region(dev->iobase, this_board->io_range); - - return 0; -} +static struct comedi_driver pcl724_driver = { + .driver_name = "pcl724", + .module = THIS_MODULE, + .attach = pcl724_attach, + .detach = comedi_legacy_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl724_board), +}; +module_comedi_driver(pcl724_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for 8255 based ISA and PC/104 DIO boards"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c deleted file mode 100644 index 24b223ca439..00000000000 --- a/drivers/staging/comedi/drivers/pcl725.c +++ /dev/null @@ -1,127 +0,0 @@ -/* - * comedi/drivers/pcl725.c - * Driver for PCL725 and clones - * David A. Schleef - */ -/* -Driver: pcl725 -Description: Advantech PCL-725 (& compatibles) -Author: ds -Status: unknown -Devices: [Advantech] PCL-725 (pcl725) -*/ - -#include "../comedidev.h" - -#include <linux/ioport.h> - -#define PCL725_SIZE 2 - -#define PCL725_DO 0 -#define PCL725_DI 1 - -static int pcl725_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl725_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcl725 = { - .driver_name = "pcl725", - .module = THIS_MODULE, - .attach = pcl725_attach, - .detach = pcl725_detach, -}; - -static int __init driver_pcl725_init_module(void) -{ - return comedi_driver_register(&driver_pcl725); -} - -static void __exit driver_pcl725_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl725); -} - -module_init(driver_pcl725_init_module); -module_exit(driver_pcl725_cleanup_module); - -static int pcl725_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - outb(s->state, dev->iobase + PCL725_DO); - } - - data[1] = s->state; - - return 2; -} - -static int pcl725_di_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = inb(dev->iobase + PCL725_DI); - - return 2; -} - -static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: pcl725: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, PCL725_SIZE, "pcl725")) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->board_name = "pcl725"; - dev->iobase = iobase; - dev->irq = 0; - - if (alloc_subdevices(dev, 2) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcl725_do_insn; - s->range_table = &range_digital; - - s = dev->subdevices + 1; - /* di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcl725_di_insn; - s->range_table = &range_digital; - - printk(KERN_INFO "\n"); - - return 0; -} - -static int pcl725_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pcl725: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, PCL725_SIZE); - - return 0; -} - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index 897cd808eeb..74f6489bd12 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -1,398 +1,455 @@ /* - comedi/drivers/pcl726.c + * pcl726.c + * Comedi driver for 6/12-Channel D/A Output and DIO cards + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ - hardware driver for Advantech cards: - card: PCL-726, PCL-727, PCL-728 - driver: pcl726, pcl727, pcl728 - and for ADLink cards: - card: ACL-6126, ACL-6128 - driver: acl6126, acl6128 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ /* -Driver: pcl726 -Description: Advantech PCL-726 & compatibles -Author: ds -Status: untested -Devices: [Advantech] PCL-726 (pcl726), PCL-727 (pcl727), PCL-728 (pcl728), - [ADLink] ACL-6126 (acl6126), ACL-6128 (acl6128) - -Interrupts are not supported. - - Options for PCL-726: - [0] - IO Base - [2]...[7] - D/A output range for channel 1-6: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA, 5: unknown (external reference) - - Options for PCL-727: - [0] - IO Base - [2]...[13] - D/A output range for channel 1-12: - 0: 0-5V, 1: 0-10V, 2: +/-5V, - 3: 4-20mA - - Options for PCL-728 and ACL-6128: - [0] - IO Base - [2], [3] - D/A output range for channel 1 and 2: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA, 5: 0-20mA - - Options for ACL-6126: - [0] - IO Base - [1] - IRQ (0=disable, 3, 5, 6, 7, 9, 10, 11, 12, 15) (currently ignored) - [2]...[7] - D/A output range for channel 1-6: - 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, - 4: 4-20mA -*/ - -/* - Thanks to Circuit Specialists for having programming info (!) on - their web page. (http://www.cir.com/) -*/ + * Driver: pcl726 + * Description: Advantech PCL-726 & compatibles + * Author: David A. Schleef <ds@schleef.org> + * Status: untested + * Devices: (Advantech) PCL-726 [pcl726] + * (Advantech) PCL-727 [pcl727] + * (Advantech) PCL-728 [pcl728] + * (ADLink) ACL-6126 [acl6126] + * (ADLink) ACL-6128 [acl6128] + * + * Configuration Options: + * [0] - IO Base + * [1] - IRQ (ACL-6126 only) + * [2] - D/A output range for channel 0 + * [3] - D/A output range for channel 1 + * + * Boards with > 2 analog output channels: + * [4] - D/A output range for channel 2 + * [5] - D/A output range for channel 3 + * [6] - D/A output range for channel 4 + * [7] - D/A output range for channel 5 + * + * Boards with > 6 analog output channels: + * [8] - D/A output range for channel 6 + * [9] - D/A output range for channel 7 + * [10] - D/A output range for channel 8 + * [11] - D/A output range for channel 9 + * [12] - D/A output range for channel 10 + * [13] - D/A output range for channel 11 + * + * For PCL-726 the D/A output ranges are: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA, 5: unknown + * + * For PCL-727: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: 4-20mA + * + * For PCL-728 and ACL-6128: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA, 5: 0-20mA + * + * For ACL-6126: + * 0: 0-5V, 1: 0-10V, 2: +/-5V, 3: +/-10V, 4: 4-20mA + */ + +#include <linux/module.h> +#include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> - -#undef ACL6126_IRQ /* no interrupt support (yet) */ - -#define PCL726_SIZE 16 -#define PCL727_SIZE 32 -#define PCL728_SIZE 8 - -#define PCL726_DAC0_HI 0 -#define PCL726_DAC0_LO 1 - -#define PCL726_DO_HI 12 -#define PCL726_DO_LO 13 -#define PCL726_DI_HI 14 -#define PCL726_DI_LO 15 +#include "comedi_fc.h" -#define PCL727_DO_HI 24 -#define PCL727_DO_LO 25 -#define PCL727_DI_HI 0 -#define PCL727_DI_LO 1 +#define PCL726_AO_MSB_REG(x) (0x00 + ((x) * 2)) +#define PCL726_AO_LSB_REG(x) (0x01 + ((x) * 2)) +#define PCL726_DO_MSB_REG 0x0c +#define PCL726_DO_LSB_REG 0x0d +#define PCL726_DI_MSB_REG 0x0e +#define PCL726_DI_LSB_REG 0x0f -static const struct comedi_lrange range_4_20mA = { 1, {RANGE_mA(4, 20)} }; -static const struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} }; +#define PCL727_DI_MSB_REG 0x00 +#define PCL727_DI_LSB_REG 0x01 +#define PCL727_DO_MSB_REG 0x18 +#define PCL727_DO_LSB_REG 0x19 static const struct comedi_lrange *const rangelist_726[] = { - &range_unipolar5, &range_unipolar10, - &range_bipolar5, &range_bipolar10, - &range_4_20mA, &range_unknown + &range_unipolar5, + &range_unipolar10, + &range_bipolar5, + &range_bipolar10, + &range_4_20mA, + &range_unknown }; static const struct comedi_lrange *const rangelist_727[] = { - &range_unipolar5, &range_unipolar10, + &range_unipolar5, + &range_unipolar10, &range_bipolar5, &range_4_20mA }; static const struct comedi_lrange *const rangelist_728[] = { - &range_unipolar5, &range_unipolar10, - &range_bipolar5, &range_bipolar10, - &range_4_20mA, &range_0_20mA + &range_unipolar5, + &range_unipolar10, + &range_bipolar5, + &range_bipolar10, + &range_4_20mA, + &range_0_20mA }; -static int pcl726_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl726_detach(struct comedi_device *dev); - struct pcl726_board { - - const char *name; /* driver name */ - int n_aochan; /* num of D/A chans */ - int num_of_ranges; /* num of ranges */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int io_range; /* len of IO space */ - char have_dio; /* 1=card have DI/DO ports */ - int di_hi; /* ports for DI/DO operations */ - int di_lo; - int do_hi; - int do_lo; - const struct comedi_lrange *const *range_type_list; - /* list of supported ranges */ + const char *name; + unsigned long io_len; + unsigned int irq_mask; + const struct comedi_lrange *const *ao_ranges; + int ao_num_ranges; + int ao_nchan; + unsigned int have_dio:1; + unsigned int is_pcl727:1; }; -static const struct pcl726_board boardtypes[] = { - {"pcl726", 6, 6, 0x0000, PCL726_SIZE, 1, - PCL726_DI_HI, PCL726_DI_LO, PCL726_DO_HI, PCL726_DO_LO, - &rangelist_726[0],}, - {"pcl727", 12, 4, 0x0000, PCL727_SIZE, 1, - PCL727_DI_HI, PCL727_DI_LO, PCL727_DO_HI, PCL727_DO_LO, - &rangelist_727[0],}, - {"pcl728", 2, 6, 0x0000, PCL728_SIZE, 0, - 0, 0, 0, 0, - &rangelist_728[0],}, - {"acl6126", 6, 5, 0x96e8, PCL726_SIZE, 1, - PCL726_DI_HI, PCL726_DI_LO, PCL726_DO_HI, PCL726_DO_LO, - &rangelist_726[0],}, - {"acl6128", 2, 6, 0x0000, PCL728_SIZE, 0, - 0, 0, 0, 0, - &rangelist_728[0],}, +static const struct pcl726_board pcl726_boards[] = { + { + .name = "pcl726", + .io_len = 0x10, + .ao_ranges = &rangelist_726[0], + .ao_num_ranges = ARRAY_SIZE(rangelist_726), + .ao_nchan = 6, + .have_dio = 1, + }, { + .name = "pcl727", + .io_len = 0x20, + .ao_ranges = &rangelist_727[0], + .ao_num_ranges = ARRAY_SIZE(rangelist_727), + .ao_nchan = 12, + .have_dio = 1, + .is_pcl727 = 1, + }, { + .name = "pcl728", + .io_len = 0x08, + .ao_num_ranges = ARRAY_SIZE(rangelist_728), + .ao_ranges = &rangelist_728[0], + .ao_nchan = 2, + }, { + .name = "acl6126", + .io_len = 0x10, + .irq_mask = 0x96e8, + .ao_num_ranges = ARRAY_SIZE(rangelist_726), + .ao_ranges = &rangelist_726[0], + .ao_nchan = 6, + .have_dio = 1, + }, { + .name = "acl6128", + .io_len = 0x08, + .ao_num_ranges = ARRAY_SIZE(rangelist_728), + .ao_ranges = &rangelist_728[0], + .ao_nchan = 2, + }, }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl726_board)) -#define this_board ((const struct pcl726_board *)dev->board_ptr) - -static struct comedi_driver driver_pcl726 = { - .driver_name = "pcl726", - .module = THIS_MODULE, - .attach = pcl726_attach, - .detach = pcl726_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl726_board), +struct pcl726_private { + const struct comedi_lrange *rangelist[12]; + unsigned int ao_readback[12]; + unsigned int cmd_running:1; }; -static int __init driver_pcl726_init_module(void) +static int pcl726_intr_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - return comedi_driver_register(&driver_pcl726); + data[1] = 0; + return insn->n; } -static void __exit driver_pcl726_cleanup_module(void) +static int pcl726_intr_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - comedi_driver_unregister(&driver_pcl726); + 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: ignored */ + + if (err) + return 4; + + return 0; } -module_init(driver_pcl726_init_module); -module_exit(driver_pcl726_cleanup_module); +static int pcl726_intr_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl726_private *devpriv = dev->private; -struct pcl726_private { + devpriv->cmd_running = 1; - int bipolar[12]; - const struct comedi_lrange *rangelist[12]; - unsigned int ao_readback[12]; -}; + return 0; +} + +static int pcl726_intr_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl726_private *devpriv = dev->private; -#define devpriv ((struct pcl726_private *)dev->private) + devpriv->cmd_running = 0; -static int pcl726_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + return 0; +} + +static irqreturn_t pcl726_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct pcl726_private *devpriv = dev->private; + + if (devpriv->cmd_running) { + pcl726_intr_cancel(dev, s); + + comedi_buf_put(s, 0); + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + comedi_event(dev, s); + } + + return IRQ_HANDLED; +} + +static int pcl726_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int hi, lo; - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { - lo = data[n] & 0xff; - hi = (data[n] >> 8) & 0xf; - if (devpriv->bipolar[chan]) - hi ^= 0x8; - /* - * the programming info did not say which order - * to write bytes. switch the order of the next - * two lines if you get glitches. - */ - outb(hi, dev->iobase + PCL726_DAC0_HI + 2 * chan); - outb(lo, dev->iobase + PCL726_DAC0_LO + 2 * chan); - devpriv->ao_readback[chan] = data[n]; + 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; + + /* bipolar data to the DAC is two's complement */ + if (comedi_chan_range_is_bipolar(s, chan, range)) + val = comedi_offset_munge(s, val); + + /* order is important, MSB then LSB */ + outb((val >> 8) & 0xff, dev->iobase + PCL726_AO_MSB_REG(chan)); + outb(val & 0xff, dev->iobase + PCL726_AO_LSB_REG(chan)); } - return n; + 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 comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); - int n; + struct pcl726_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - for (n = 0; n < insn->n; n++) - data[n] = devpriv->ao_readback[chan]; - return n; + 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) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; + const struct pcl726_board *board = comedi_board(dev); + unsigned int val; - data[1] = inb(dev->iobase + this_board->di_lo) | - (inb(dev->iobase + this_board->di_hi) << 8); + if (board->is_pcl727) { + val = inb(dev->iobase + PCL727_DI_LSB_REG); + val |= (inb(dev->iobase + PCL727_DI_MSB_REG) << 8); + } else { + val = inb(dev->iobase + PCL726_DI_LSB_REG); + val |= (inb(dev->iobase + PCL726_DI_MSB_REG) << 8); + } - return 2; + data[1] = val; + + return insn->n; } static int pcl726_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + const struct pcl726_board *board = comedi_board(dev); + unsigned long io = dev->iobase; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (board->is_pcl727) { + if (mask & 0x00ff) + outb(s->state & 0xff, io + PCL727_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), io + PCL727_DO_MSB_REG); + } else { + if (mask & 0x00ff) + outb(s->state & 0xff, io + PCL726_DO_LSB_REG); + if (mask & 0xff00) + outb((s->state >> 8), io + PCL726_DO_MSB_REG); + } } - if (data[1] & 0x00ff) - outb(s->state & 0xff, dev->iobase + this_board->do_lo); - if (data[1] & 0xff00) - outb((s->state >> 8), dev->iobase + this_board->do_hi); data[1] = s->state; - return 2; + return insn->n; } -static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pcl726_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { + const struct pcl726_board *board = comedi_board(dev); + struct pcl726_private *devpriv; struct comedi_subdevice *s; - unsigned long iobase; - unsigned int iorange; - int ret, i; -#ifdef ACL6126_IRQ - unsigned int irq; -#endif - - iobase = it->options[0]; - iorange = this_board->io_range; - printk(KERN_WARNING "comedi%d: pcl726: board=%s, 0x%03lx ", dev->minor, - this_board->name, iobase); - if (!request_region(iobase, iorange, "pcl726")) { - printk(KERN_WARNING "I/O port conflict\n"); - return -EIO; - } + int subdev; + int ret; + int i; - dev->iobase = iobase; - - dev->board_name = this_board->name; + ret = comedi_request_region(dev, it->options[0], board->io_len); + if (ret) + return ret; - ret = alloc_private(dev, sizeof(struct pcl726_private)); - if (ret < 0) + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - for (i = 0; i < 12; i++) { - devpriv->bipolar[i] = 0; - devpriv->rangelist[i] = &range_unknown; - } - -#ifdef ACL6126_IRQ - irq = 0; - if (boardtypes[board].IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - devpriv->first_chan = 2; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & boardtypes[board].IRQbits) == 0) { - printk(KERN_WARNING - ", IRQ %d is out of allowed range," - " DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq(irq, interrupt_pcl818, 0, - "pcl726", dev)) { - printk(KERN_WARNING - ", unable to allocate IRQ %d," - " DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(", irq=%d", irq); - } - } + /* + * Hook up the external trigger source interrupt only if the + * user config option is valid and the board supports interrupts. + */ + if (it->options[1] && (board->irq_mask & (1 << it->options[1]))) { + ret = request_irq(it->options[1], pcl726_interrupt, 0, + dev->board_name, dev); + if (ret == 0) { + /* External trigger source is from Pin-17 of CN3 */ + dev->irq = it->options[1]; } } - dev->irq = irq; -#endif + /* setup the per-channel analog output range_table_list */ + for (i = 0; i < 12; i++) { + unsigned int opt = it->options[2 + i]; - printk("\n"); + if (opt < board->ao_num_ranges && i < board->ao_nchan) + devpriv->rangelist[i] = board->ao_ranges[opt]; + else + devpriv->rangelist[i] = &range_unknown; + } - ret = alloc_subdevices(dev, 3); - if (ret < 0) + subdev = board->have_dio ? 3 : 1; + if (dev->irq) + subdev++; + ret = comedi_alloc_subdevices(dev, subdev); + if (ret) return ret; - s = dev->subdevices + 0; - /* ao */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = this_board->n_aochan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->insn_write = pcl726_ao_insn; - s->insn_read = pcl726_ao_insn_read; - s->range_table_list = devpriv->rangelist; - for (i = 0; i < this_board->n_aochan; i++) { - int j; - - j = it->options[2 + 1]; - if ((j < 0) || (j >= this_board->num_of_ranges)) { - printk - ("Invalid range for channel %d! Must be 0<=%d<%d\n", - i, j, this_board->num_of_ranges - 1); - j = 0; - } - devpriv->rangelist[i] = this_board->range_type_list[j]; - if (devpriv->rangelist[i]->range[0].min == - -devpriv->rangelist[i]->range[0].max) - devpriv->bipolar[i] = 1; /* bipolar range */ - } + subdev = 0; - s = dev->subdevices + 1; - /* di */ - if (!this_board->have_dio) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 1; - s->insn_bits = pcl726_di_insn_bits; - s->range_table = &range_digital; + /* Analog Output subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->ao_nchan; + s->maxdata = 0x0fff; + s->range_table_list = devpriv->rangelist; + s->insn_write = pcl726_ao_insn_write; + s->insn_read = pcl726_ao_insn_read; + + if (board->have_dio) { + /* Digital Input subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->insn_bits = pcl726_di_insn_bits; + s->range_table = &range_digital; + + /* Digital Output subdevice */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->insn_bits = pcl726_do_insn_bits; + s->range_table = &range_digital; } - s = dev->subdevices + 2; - /* do */ - if (!this_board->have_dio) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = 16; - s->maxdata = 1; - s->len_chanlist = 1; - s->insn_bits = pcl726_do_insn_bits; - s->range_table = &range_digital; + if (dev->irq) { + /* Digial Input subdevice - Interrupt support */ + s = &dev->subdevices[subdev++]; + 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->insn_bits = pcl726_intr_insn_bits; + s->len_chanlist = 1; + s->do_cmdtest = pcl726_intr_cmdtest; + s->do_cmd = pcl726_intr_cmd; + s->cancel = pcl726_intr_cancel; } return 0; } -static int pcl726_detach(struct comedi_device *dev) -{ -/* printk("comedi%d: pcl726: remove\n",dev->minor); */ - -#ifdef ACL6126_IRQ - if (dev->irq) - free_irq(dev->irq, dev); -#endif - - if (dev->iobase) - release_region(dev->iobase, this_board->io_range); - - return 0; -} +static struct comedi_driver pcl726_driver = { + .driver_name = "pcl726", + .module = THIS_MODULE, + .attach = pcl726_attach, + .detach = comedi_legacy_detach, + .board_name = &pcl726_boards[0].name, + .num_names = ARRAY_SIZE(pcl726_boards), + .offset = sizeof(struct pcl726_board), +}; +module_comedi_driver(pcl726_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Advantech PCL-726 & compatibles"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index c9682d614e0..7fb044ce399 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -3,181 +3,335 @@ * Driver for Advantech PCL-730 and clones * José Luis Sánchez */ -/* -Driver: pcl730 -Description: Advantech PCL-730 (& compatibles) -Author: José Luis Sánchez (jsanchezv@teleline.es) -Status: untested -Devices: [Advantech] PCL-730 (pcl730), [ICP] ISO-730 (iso730), - [Adlink] ACL-7130 (acl7130) -Interrupts are not supported. -The ACL-7130 card have an 8254 timer/counter not supported by this driver. -*/ +/* + * Driver: pcl730 + * Description: Advantech PCL-730 (& compatibles) + * Devices: (Advantech) PCL-730 [pcl730] + * (ICP) ISO-730 [iso730] + * (Adlink) ACL-7130 [acl7130] + * (Advantech) PCM-3730 [pcm3730] + * (Advantech) PCL-725 [pcl725] + * (ICP) P8R8-DIO [p16r16dio] + * (Adlink) ACL-7225b [acl7225b] + * (ICP) P16R16-DIO [p16r16dio] + * (Advantech) PCL-733 [pcl733] + * (Advantech) PCL-734 [pcl734] + * (Diamond Systems) OPMM-1616-XT [opmm-1616-xt] + * (Diamond Systems) PEARL-MM-P [prearl-mm-p] + * Author: José Luis Sánchez (jsanchezv@teleline.es) + * Status: untested + * + * Configuration options: + * [0] - I/O port base + * + * Interrupts are not supported. + * The ACL-7130 card has an 8254 timer/counter not supported by this driver. + */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - -#define PCL730_SIZE 4 -#define ACL7130_SIZE 8 -#define PCL730_IDIO_LO 0 /* Isolated Digital I/O low byte (ID0-ID7) */ -#define PCL730_IDIO_HI 1 /* Isolated Digital I/O high byte (ID8-ID15) */ -#define PCL730_DIO_LO 2 /* TTL Digital I/O low byte (D0-D7) */ -#define PCL730_DIO_HI 3 /* TTL Digital I/O high byte (D8-D15) */ - -static int pcl730_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl730_detach(struct comedi_device *dev); +/* + * Register map + * + * The register map varies slightly depending on the board type but + * all registers are 8-bit. + * + * The boardinfo 'io_range' is used to allow comedi to request the + * proper range required by the board. + * + * The comedi_subdevice 'private' data is used to pass the register + * offset to the (*insn_bits) functions to read/write the correct + * registers. + * + * The basic register mapping looks like this: + * + * BASE+0 Isolated outputs 0-7 (write) / inputs 0-7 (read) + * BASE+1 Isolated outputs 8-15 (write) / inputs 8-15 (read) + * BASE+2 TTL outputs 0-7 (write) / inputs 0-7 (read) + * BASE+3 TTL outputs 8-15 (write) / inputs 8-15 (read) + * + * The pcm3730 board does not have register BASE+1. + * + * The pcl725 and p8r8dio only have registers BASE+0 and BASE+1: + * + * BASE+0 Isolated outputs 0-7 (write) (read back on p8r8dio) + * BASE+1 Isolated inputs 0-7 (read) + * + * The acl7225b and p16r16dio boards have this register mapping: + * + * BASE+0 Isolated outputs 0-7 (write) (read back) + * BASE+1 Isolated outputs 8-15 (write) (read back) + * BASE+2 Isolated inputs 0-7 (read) + * BASE+3 Isolated inputs 8-15 (read) + * + * The pcl733 and pcl733 boards have this register mapping: + * + * BASE+0 Isolated outputs 0-7 (write) or inputs 0-7 (read) + * BASE+1 Isolated outputs 8-15 (write) or inputs 8-15 (read) + * BASE+2 Isolated outputs 16-23 (write) or inputs 16-23 (read) + * BASE+3 Isolated outputs 24-31 (write) or inputs 24-31 (read) + * + * The opmm-1616-xt board has this register mapping: + * + * BASE+0 Isolated outputs 0-7 (write) (read back) + * BASE+1 Isolated outputs 8-15 (write) (read back) + * BASE+2 Isolated inputs 0-7 (read) + * BASE+3 Isolated inputs 8-15 (read) + * + * These registers are not currently supported: + * + * BASE+2 Relay select register (write) + * BASE+3 Board reset control register (write) + * BASE+4 Interrupt control register (write) + * BASE+4 Change detect 7-0 status register (read) + * BASE+5 LED control register (write) + * BASE+5 Change detect 15-8 status register (read) + * + * The pearl-mm-p board has this register mapping: + * + * BASE+0 Isolated outputs 0-7 (write) + * BASE+1 Isolated outputs 8-15 (write) + */ struct pcl730_board { - - const char *name; /* board name */ - unsigned int io_range; /* len of I/O space */ -}; - -static const struct pcl730_board boardtypes[] = { - {"pcl730", PCL730_SIZE,}, - {"iso730", PCL730_SIZE,}, - {"acl7130", ACL7130_SIZE,}, + const char *name; + unsigned int io_range; + unsigned is_pcl725:1; + unsigned is_acl7225b:1; + unsigned has_readback:1; + unsigned has_ttl_io:1; + int n_subdevs; + int n_iso_out_chan; + int n_iso_in_chan; + int n_ttl_chan; }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl730_board)) -#define this_board ((const struct pcl730_board *)dev->board_ptr) - -static struct comedi_driver driver_pcl730 = { - .driver_name = "pcl730", - .module = THIS_MODULE, - .attach = pcl730_attach, - .detach = pcl730_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl730_board), +static const struct pcl730_board pcl730_boards[] = { + { + .name = "pcl730", + .io_range = 0x04, + .has_ttl_io = 1, + .n_subdevs = 4, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + .n_ttl_chan = 16, + }, { + .name = "iso730", + .io_range = 0x04, + .n_subdevs = 4, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + .n_ttl_chan = 16, + }, { + .name = "acl7130", + .io_range = 0x08, + .has_ttl_io = 1, + .n_subdevs = 4, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + .n_ttl_chan = 16, + }, { + .name = "pcm3730", + .io_range = 0x04, + .has_ttl_io = 1, + .n_subdevs = 4, + .n_iso_out_chan = 8, + .n_iso_in_chan = 8, + .n_ttl_chan = 16, + }, { + .name = "pcl725", + .io_range = 0x02, + .is_pcl725 = 1, + .n_subdevs = 2, + .n_iso_out_chan = 8, + .n_iso_in_chan = 8, + }, { + .name = "p8r8dio", + .io_range = 0x02, + .is_pcl725 = 1, + .has_readback = 1, + .n_subdevs = 2, + .n_iso_out_chan = 8, + .n_iso_in_chan = 8, + }, { + .name = "acl7225b", + .io_range = 0x08, /* only 4 are used */ + .is_acl7225b = 1, + .has_readback = 1, + .n_subdevs = 2, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + }, { + .name = "p16r16dio", + .io_range = 0x04, + .is_acl7225b = 1, + .has_readback = 1, + .n_subdevs = 2, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + }, { + .name = "pcl733", + .io_range = 0x04, + .n_subdevs = 1, + .n_iso_in_chan = 32, + }, { + .name = "pcl734", + .io_range = 0x04, + .n_subdevs = 1, + .n_iso_out_chan = 32, + }, { + .name = "opmm-1616-xt", + .io_range = 0x10, + .is_acl7225b = 1, + .has_readback = 1, + .n_subdevs = 2, + .n_iso_out_chan = 16, + .n_iso_in_chan = 16, + }, { + .name = "pearl-mm-p", + .io_range = 0x02, + .n_subdevs = 1, + .n_iso_out_chan = 16, + }, }; -static int __init driver_pcl730_init_module(void) -{ - return comedi_driver_register(&driver_pcl730); -} - -static void __exit driver_pcl730_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl730); -} - -module_init(driver_pcl730_init_module); -module_exit(driver_pcl730_cleanup_module); - -static int pcl730_do_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcl730_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); + unsigned long reg = (unsigned long)s->private; + unsigned int mask; + + mask = comedi_dio_update_state(s, data); + if (mask) { + if (mask & 0x00ff) + outb(s->state & 0xff, dev->iobase + reg); + if ((mask & 0xff00) && (s->n_chan > 8)) + outb((s->state >> 8) & 0xff, dev->iobase + reg + 1); + if ((mask & 0xff0000) && (s->n_chan > 16)) + outb((s->state >> 16) & 0xff, dev->iobase + reg + 2); + if ((mask & 0xff000000) && (s->n_chan > 24)) + outb((s->state >> 24) & 0xff, dev->iobase + reg + 3); } - if (data[0] & 0x00ff) - outb(s->state & 0xff, - dev->iobase + ((unsigned long)s->private)); - if (data[0] & 0xff00) - outb((s->state >> 8), - dev->iobase + ((unsigned long)s->private) + 1); data[1] = s->state; - return 2; + return insn->n; } -static int pcl730_di_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static unsigned int pcl730_get_bits(struct comedi_device *dev, + struct comedi_subdevice *s) { - if (insn->n != 2) - return -EINVAL; + unsigned long reg = (unsigned long)s->private; + unsigned int val; + + val = inb(dev->iobase + reg); + if (s->n_chan > 8) + val |= (inb(dev->iobase + reg + 1) << 8); + if (s->n_chan > 16) + val |= (inb(dev->iobase + reg + 2) << 16); + if (s->n_chan > 24) + val |= (inb(dev->iobase + reg + 3) << 24); + + return val; +} - data[1] = inb(dev->iobase + ((unsigned long)s->private)) | - (inb(dev->iobase + ((unsigned long)s->private) + 1) << 8); +static int pcl730_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = pcl730_get_bits(dev, s); - return 2; + return insn->n; } -static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int pcl730_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { + const struct pcl730_board *board = comedi_board(dev); struct comedi_subdevice *s; - unsigned long iobase; - unsigned int iorange; - - iobase = it->options[0]; - iorange = this_board->io_range; - printk(KERN_INFO "comedi%d: pcl730: board=%s 0x%04lx ", dev->minor, - this_board->name, iobase); - if (!request_region(iobase, iorange, "pcl730")) { - printk("I/O port conflict\n"); - return -EIO; + int subdev; + int ret; + + ret = comedi_request_region(dev, it->options[0], board->io_range); + if (ret) + return ret; + + ret = comedi_alloc_subdevices(dev, board->n_subdevs); + if (ret) + return ret; + + subdev = 0; + + if (board->n_iso_out_chan) { + /* Isolated Digital Outputs */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_iso_out_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl730_do_insn_bits; + s->private = (void *)0; + + /* get the initial state if supported */ + if (board->has_readback) + s->state = pcl730_get_bits(dev, s); } - dev->board_name = this_board->name; - dev->iobase = iobase; - dev->irq = 0; - - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* Isolated do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = pcl730_do_insn; - s->range_table = &range_digital; - s->private = (void *)PCL730_IDIO_LO; - - s = dev->subdevices + 1; - /* Isolated di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = pcl730_di_insn; - s->range_table = &range_digital; - s->private = (void *)PCL730_IDIO_LO; - - s = dev->subdevices + 2; - /* TTL do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = pcl730_do_insn; - s->range_table = &range_digital; - s->private = (void *)PCL730_DIO_LO; - - s = dev->subdevices + 3; - /* TTL di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 16; - s->insn_bits = pcl730_di_insn; - s->range_table = &range_digital; - s->private = (void *)PCL730_DIO_LO; - - printk(KERN_INFO "\n"); - return 0; -} - -static int pcl730_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pcl730: remove\n", dev->minor); + if (board->n_iso_in_chan) { + /* Isolated Digital Inputs */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = board->n_iso_in_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl730_di_insn_bits; + s->private = board->is_acl7225b ? (void *)2 : + board->is_pcl725 ? (void *)1 : (void *)0; + } - if (dev->iobase) - release_region(dev->iobase, this_board->io_range); + if (board->has_ttl_io) { + /* TTL Digital Outputs */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = board->n_ttl_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl730_do_insn_bits; + s->private = (void *)2; + + /* TTL Digital Inputs */ + s = &dev->subdevices[subdev++]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = board->n_ttl_chan; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl730_di_insn_bits; + s->private = (void *)2; + } return 0; } +static struct comedi_driver pcl730_driver = { + .driver_name = "pcl730", + .module = THIS_MODULE, + .attach = pcl730_attach, + .detach = comedi_legacy_detach, + .board_name = &pcl730_boards[0].name, + .num_names = ARRAY_SIZE(pcl730_boards), + .offset = sizeof(struct pcl730_board), +}; +module_comedi_driver(pcl730_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 09ff4723b22..4c1b9470647 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -108,19 +108,18 @@ * 3= 20V unipolar inputs */ +#include <linux/module.h> #include <linux/interrupt.h> #include <linux/gfp.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/ioport.h> +#include <linux/io.h> #include <asm/dma.h> +#include "comedi_fc.h" #include "8253.h" -/* if this is defined then a lot of messages is printed */ -#undef PCL812_EXTDEBUG - /* hardware types of the cards */ #define boardPCL812PG 0 /* and ACL-8112PG */ #define boardPCL813B 1 @@ -132,761 +131,681 @@ #define boardACL8216 8 /* and ICP DAS A-826PG */ #define boardA821 9 /* PGH, PGL, PGL/NDA versions */ -#define PCLx1x_IORANGE 16 - -#define PCL812_CTR0 0 -#define PCL812_CTR1 1 -#define PCL812_CTR2 2 -#define PCL812_CTRCTL 3 -#define PCL812_AD_LO 4 -#define PCL812_DA1_LO 4 -#define PCL812_AD_HI 5 -#define PCL812_DA1_HI 5 -#define PCL812_DA2_LO 6 -#define PCL812_DI_LO 6 -#define PCL812_DA2_HI 7 -#define PCL812_DI_HI 7 -#define PCL812_CLRINT 8 -#define PCL812_GAIN 9 -#define PCL812_MUX 10 -#define PCL812_MODE 11 -#define PCL812_CNTENABLE 10 -#define PCL812_SOFTTRIG 12 -#define PCL812_DO_LO 13 -#define PCL812_DO_HI 14 - -#define PCL812_DRDY 0x10 /* =0 data ready */ - -#define ACL8216_STATUS 8 /* 5. bit signalize data ready */ - -#define ACL8216_DRDY 0x20 /* =0 data ready */ +/* + * Register I/O map + */ +#define PCL812_TIMER_BASE 0x00 +#define PCL812_AI_LSB_REG 0x04 +#define PCL812_AI_MSB_REG 0x05 +#define PCL812_AI_MSB_DRDY (1 << 4) +#define PCL812_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL812_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL812_DI_LSB_REG 0x06 +#define PCL812_DI_MSB_REG 0x07 +#define PCL812_STATUS_REG 0x08 +#define PCL812_STATUS_DRDY (1 << 5) +#define PCL812_RANGE_REG 0x09 +#define PCL812_MUX_REG 0x0a +#define PCL812_MUX_CHAN(x) ((x) << 0) +#define PCL812_MUX_CS0 (1 << 4) +#define PCL812_MUX_CS1 (1 << 5) +#define PCL812_CTRL_REG 0x0b +#define PCL812_CTRL_DISABLE_TRIG (0 << 0) +#define PCL812_CTRL_SOFT_TRIG (1 << 0) +#define PCL812_CTRL_PACER_DMA_TRIG (2 << 0) +#define PCL812_CTRL_PACER_EOC_TRIG (6 << 0) +#define PCL812_SOFTTRIG_REG 0x0c +#define PCL812_DO_LSB_REG 0x0d +#define PCL812_DO_MSB_REG 0x0e #define MAX_CHANLIST_LEN 256 /* length of scan list */ -static const struct comedi_lrange range_pcl812pg_ai = { 5, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(0.3125), - } +static const struct comedi_lrange range_pcl812pg_ai = { + 5, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_pcl812pg2_ai = { 5, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_pcl812pg2_ai = { + 5, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range812_bipolar1_25 = { 1, { - BIP_RANGE(1.25), - } +static const struct comedi_lrange range812_bipolar1_25 = { + 1, { + BIP_RANGE(1.25) + } }; -static const struct comedi_lrange range812_bipolar0_625 = { 1, { - BIP_RANGE - (0.625), - } +static const struct comedi_lrange range812_bipolar0_625 = { + 1, { + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range812_bipolar0_3125 = { 1, { - BIP_RANGE - (0.3125), - } +static const struct comedi_lrange range812_bipolar0_3125 = { + 1, { + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_pcl813b_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_pcl813b_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range_pcl813b2_ai = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_pcl813b2_ai = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_iso813_1_ai = { 5, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - BIP_RANGE(0.3125), - } +static const struct comedi_lrange range_iso813_1_ai = { + 5, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125) + } }; -static const struct comedi_lrange range_iso813_1_2_ai = { 5, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - UNI_RANGE(0.625), - } +static const struct comedi_lrange range_iso813_1_2_ai = { + 5, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + UNI_RANGE(0.625) + } }; -static const struct comedi_lrange range_iso813_2_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_iso813_2_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range_iso813_2_2_ai = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_iso813_2_2_ai = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_acl8113_1_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_acl8113_1_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range_acl8113_1_2_ai = { 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_acl8113_1_2_ai = { + 4, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; -static const struct comedi_lrange range_acl8113_2_ai = { 3, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - } +static const struct comedi_lrange range_acl8113_2_ai = { + 3, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } }; -static const struct comedi_lrange range_acl8113_2_2_ai = { 3, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - } +static const struct comedi_lrange range_acl8113_2_2_ai = { + 3, { + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5) + } }; -static const struct comedi_lrange range_acl8112dg_ai = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10), - } +static const struct comedi_lrange range_acl8112dg_ai = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; -static const struct comedi_lrange range_acl8112hg_ai = { 12, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - } +static const struct comedi_lrange range_acl8112hg_ai = { + 12, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_a821pgh_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - } +static const struct comedi_lrange range_a821pgh_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005) + } }; -static int pcl812_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl812_detach(struct comedi_device *dev); - struct pcl812_board { - - const char *name; /* board name */ - int board_type; /* type of this board */ - int n_aichan; /* num of AI chans in S.E. */ - int n_aichan_diff; /* DIFF num of chans */ - int n_aochan; /* num of DA chans */ - int n_dichan; /* DI and DO chans */ - int n_dochan; - int ai_maxdata; /* AI resolution */ - unsigned int ai_ns_min; /* max sample speed of card v ns */ - unsigned int i8254_osc_base; /* clock base */ - const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ - unsigned int IRQbits; /* allowed IRQ */ - unsigned char DMAbits; /* allowed DMA chans */ - unsigned char io_range; /* iorange for this board */ - unsigned char haveMPC508; /* 1=board use MPC508A multiplexor */ + const char *name; + int board_type; + int n_aichan; + int n_aochan; + unsigned int ai_ns_min; + const struct comedi_lrange *rangelist_ai; + unsigned int IRQbits; + unsigned int has_dma:1; + unsigned int has_16bit_ai:1; + unsigned int has_mpc508_mux:1; + unsigned int has_dio:1; }; static const struct pcl812_board boardtypes[] = { - {"pcl812", boardPCL812, 16, 0, 2, 16, 16, 0x0fff, - 33000, 500, &range_bipolar10, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl812pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 33000, 500, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112pg", boardPCL812PG, 16, 0, 2, 16, 16, 0x0fff, - 10000, 500, &range_pcl812pg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"acl8112dg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"acl8112hg", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a821pgl", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, 500, &range_pcl813b_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pglnda", boardA821, 16, 8, 0, 0, 0, 0x0fff, - 10000, 500, &range_pcl813b_ai, NULL, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a821pgh", boardA821, 16, 8, 1, 16, 16, 0x0fff, - 10000, 500, &range_a821pgh_ai, &range_unipolar5, - 0x000c, 0x00, PCLx1x_IORANGE, 0}, - {"a822pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a822pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 10000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgl", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, 500, &range_acl8112dg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"a823pgh", boardACL8112, 16, 8, 2, 16, 16, 0x0fff, - 8000, 500, &range_acl8112hg_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, - {"pcl813", boardPCL813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"pcl813b", boardPCL813B, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_pcl813b_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8113", boardACL8113, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_acl8113_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"iso813", boardISO813, 32, 0, 0, 0, 0, 0x0fff, - 0, 0, &range_iso813_1_ai, NULL, - 0x0000, 0x00, PCLx1x_IORANGE, 0}, - {"acl8216", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, 500, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 1}, - {"a826pg", boardACL8216, 16, 8, 2, 16, 16, 0xffff, - 10000, 500, &range_pcl813b2_ai, &range_unipolar5, - 0xdcfc, 0x0a, PCLx1x_IORANGE, 0}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl812_board)) -#define this_board ((const struct pcl812_board *)dev->board_ptr) - -static struct comedi_driver driver_pcl812 = { - .driver_name = "pcl812", - .module = THIS_MODULE, - .attach = pcl812_attach, - .detach = pcl812_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl812_board), + { + .name = "pcl812", + .board_type = boardPCL812, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_bipolar10, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl812pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 33000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112pg", + .board_type = boardPCL812PG, + .n_aichan = 16, + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl812pg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "acl8112dg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "acl8112hg", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a821pgl", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a821pglnda", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b_ai, + .IRQbits = 0x000c, + }, { + .name = "a821pgh", + .board_type = boardA821, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 1, + .ai_ns_min = 10000, + .rangelist_ai = &range_a821pgh_ai, + .IRQbits = 0x000c, + .has_dio = 1, + }, { + .name = "a822pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a822pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgl", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112dg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "a823pgh", + .board_type = boardACL8112, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 8000, + .rangelist_ai = &range_acl8112hg_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_dio = 1, + }, { + .name = "pcl813", + .board_type = boardPCL813, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "pcl813b", + .board_type = boardPCL813B, + .n_aichan = 32, + .rangelist_ai = &range_pcl813b_ai, + }, { + .name = "acl8113", + .board_type = boardACL8113, + .n_aichan = 32, + .rangelist_ai = &range_acl8113_1_ai, + }, { + .name = "iso813", + .board_type = boardISO813, + .n_aichan = 32, + .rangelist_ai = &range_iso813_1_ai, + }, { + .name = "acl8216", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_mpc508_mux = 1, + .has_dio = 1, + }, { + .name = "a826pg", + .board_type = boardACL8216, + .n_aichan = 16, /* 8 differential */ + .n_aochan = 2, + .ai_ns_min = 10000, + .rangelist_ai = &range_pcl813b2_ai, + .IRQbits = 0xdcfc, + .has_dma = 1, + .has_16bit_ai = 1, + .has_dio = 1, + }, }; -static int __init driver_pcl812_init_module(void) -{ - return comedi_driver_register(&driver_pcl812); -} - -static void __exit driver_pcl812_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl812); -} - -module_init(driver_pcl812_init_module); -module_exit(driver_pcl812_cleanup_module); - struct pcl812_private { - - unsigned char valid; /* =1 device is OK */ unsigned char dma; /* >0 use dma ( usedDMA channel) */ - unsigned char use_diff; /* =1 diff inputs */ - unsigned char use_MPC; /* 1=board uses MPC508A multiplexor */ - unsigned char use_ext_trg; /* 1=board uses external trigger */ unsigned char range_correction; /* =1 we must add 1 to range number */ - unsigned char old_chan_reg; /* lastly used chan/gain pair */ - unsigned char old_gain_reg; + unsigned int last_ai_chanspec; unsigned char mode_reg_int; /* there is stored INT number for some card */ - unsigned char ai_neverending; /* =1 we do unlimited AI */ - unsigned char ai_eos; /* 1=EOS wake up */ - unsigned char ai_dma; /* =1 we use DMA */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - unsigned int ai_scans; /* len of scanlist */ unsigned int ai_act_scan; /* how many scans we finished */ - unsigned int ai_chanlist[MAX_CHANLIST_LEN]; /* our copy of channel/range list */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int ai_flags; /* flaglist */ - unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ - unsigned int ai_is16b; /* =1 we have 16 bit card */ + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* PTR to DMA buf */ - unsigned int dmapages[2]; /* how many pages we have allocated */ unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */ - unsigned int hwdmasize[2]; /* DMA buf size in bytes */ unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */ int next_dma_buf; /* which buffer is next to use */ unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */ unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */ unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */ unsigned int ao_readback[2]; /* data for AO readback */ + unsigned int divisor1; + unsigned int divisor2; + unsigned int use_diff:1; + unsigned int use_mpc508:1; + unsigned int use_ext_trg:1; + unsigned int ai_dma:1; + unsigned int ai_eos:1; }; -#define devpriv ((struct pcl812_private *)dev->private) - -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait); -static int pcl812_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -/* -============================================================================== -*/ -static int pcl812_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers) { - int n; - int timeout, hi; - - /* select software trigger */ - outb(devpriv->mode_reg_int | 1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - hi = inb(dev->iobase + PCL812_AD_HI); - if (!(hi & PCL812_DRDY)) - goto conv_finish; - udelay(1); - } - printk - ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n", - dev->minor, dev->board_name, dev->iobase); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return -ETIME; - -conv_finish: - data[n] = ((hi & 0xf) << 8) | inb(dev->iobase + PCL812_AD_LO); + struct pcl812_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL812_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); + + if (load_timers) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - return n; } -/* -============================================================================== -*/ -static int acl8216_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - int n; - int timeout; - - /* select software trigger */ - outb(1, dev->iobase + PCL812_MODE); - /* select channel and renge */ - setup_range_channel(dev, s, insn->chanspec, 1); - for (n = 0; n < insn->n; n++) { - /* start conversion */ - outb(255, dev->iobase + PCL812_SOFTTRIG); - udelay(5); - timeout = 50; /* wait max 50us, it must finish under 33us */ - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) - goto conv_finish; - udelay(1); + struct pcl812_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; + + /* we use EOS, so adapt DMA buffer to one scan */ + if (devpriv->ai_eos) { + devpriv->dmabytestomove[0] = cfc_bytes_per_scan(s); + devpriv->dmabytestomove[1] = cfc_bytes_per_scan(s); + devpriv->dma_runs_to_end = 1; + } else { + devpriv->dmabytestomove[0] = devpriv->hwdmasize; + devpriv->dmabytestomove[1] = devpriv->hwdmasize; + if (s->async->prealloc_bufsz < devpriv->hwdmasize) { + devpriv->dmabytestomove[0] = + s->async->prealloc_bufsz; + devpriv->dmabytestomove[1] = + s->async->prealloc_bufsz; + } + if (cmd->stop_src == TRIG_NONE) { + devpriv->dma_runs_to_end = 1; + } else { + /* how many samples we must transfer? */ + bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + + /* how many DMA pages we must fill */ + devpriv->dma_runs_to_end = + bytes / devpriv->dmabytestomove[0]; + + /* on last dma transfer must be moved */ + devpriv->last_dma_run = + bytes % devpriv->dmabytestomove[0]; + if (devpriv->dma_runs_to_end == 0) + devpriv->dmabytestomove[0] = + devpriv->last_dma_run; + devpriv->dma_runs_to_end--; } - printk - ("comedi%d: pcl812: (%s at 0x%lx) A/D insn read timeout\n", - dev->minor, dev->board_name, dev->iobase); - outb(0, dev->iobase + PCL812_MODE); - return -ETIME; - -conv_finish: - data[n] = - (inb(dev->iobase + - PCL812_AD_HI) << 8) | inb(dev->iobase + PCL812_AD_LO); } - outb(0, dev->iobase + PCL812_MODE); - return n; + if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) { + devpriv->dmabytestomove[0] = devpriv->hwdmasize; + devpriv->ai_eos = 0; + } + if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) { + devpriv->dmabytestomove[1] = devpriv->hwdmasize; + devpriv->ai_eos = 0; + } + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } -/* -============================================================================== -*/ -static int pcl812_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - int chan = CR_CHAN(insn->chanspec); - int i; + struct pcl812_private *devpriv = dev->private; + unsigned long dma_flags; - for (i = 0; i < insn->n; i++) { - outb((data[i] & 0xff), - dev->iobase + (chan ? PCL812_DA2_LO : PCL812_DA1_LO)); - outb((data[i] >> 8) & 0x0f, - dev->iobase + (chan ? PCL812_DA2_HI : PCL812_DA1_HI)); - devpriv->ao_readback[chan] = data[i]; + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + disable_dma(devpriv->dma); + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->ai_eos) { + set_dma_count(devpriv->dma, + devpriv->dmabytestomove[devpriv->next_dma_buf]); + } else { + if (devpriv->dma_runs_to_end) { + set_dma_count(devpriv->dma, + devpriv->dmabytestomove[devpriv-> + next_dma_buf]); + } else { + set_dma_count(devpriv->dma, devpriv->last_dma_run); + } + devpriv->dma_runs_to_end--; } - - return i; + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } -/* -============================================================================== -*/ -static int pcl812_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_set_chan_range(struct comedi_device *dev, + unsigned int chanspec, char wait) { - int chan = CR_CHAN(insn->chanspec); - int i; + struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int mux = 0; - for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[chan]; + if (chanspec == devpriv->last_ai_chanspec) + return; + + devpriv->last_ai_chanspec = chanspec; - return i; + if (devpriv->use_mpc508) { + if (devpriv->use_diff) { + mux |= PCL812_MUX_CS0 | PCL812_MUX_CS1; + } else { + if (chan < 8) + mux |= PCL812_MUX_CS0; + else + mux |= PCL812_MUX_CS1; + } + } + + outb(mux | PCL812_MUX_CHAN(chan), dev->iobase + PCL812_MUX_REG); + outb(range + devpriv->range_correction, dev->iobase + PCL812_RANGE_REG); + + if (wait) + /* + * XXX this depends on selected range and can be very long for + * some high gain ranges! + */ + udelay(devpriv->max_812_ai_mode0_rangewait); } -/* -============================================================================== -*/ -static int pcl812_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl812_ai_clear_eoc(struct comedi_device *dev) { - if (insn->n != 2) - return -EINVAL; - - data[1] = inb(dev->iobase + PCL812_DI_LO); - data[1] |= inb(dev->iobase + PCL812_DI_HI) << 8; + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL812_STATUS_REG); +} - return 2; +static void pcl812_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(255, dev->iobase + PCL812_SOFTTRIG_REG); } -/* -============================================================================== -*/ -static int pcl812_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static unsigned int pcl812_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) { - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - outb(s->state & 0xff, dev->iobase + PCL812_DO_LO); - outb((s->state >> 8), dev->iobase + PCL812_DO_HI); - } - data[1] = s->state; + unsigned int val; - return 2; + val = inb(dev->iobase + PCL812_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL812_AI_LSB_REG); + + return val & s->maxdata; } -#ifdef PCL812_EXTDEBUG -/* -============================================================================== -*/ -static void pcl812_cmdtest_out(int e, struct comedi_cmd *cmd) +static int pcl812_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - printk(KERN_INFO "pcl812 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, - cmd->start_src, cmd->scan_begin_src, cmd->convert_src); - printk(KERN_INFO "pcl812 e=%d startarg=%d scanarg=%d convarg=%d\n", e, - cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); - printk(KERN_INFO "pcl812 e=%d stopsrc=%x scanend=%x\n", e, - cmd->stop_src, cmd->scan_end_src); - printk(KERN_INFO "pcl812 e=%d stoparg=%d scanendarg=%d " - "chanlistlen=%d\n", e, cmd->stop_arg, cmd->scan_end_arg, - cmd->chanlist_len); + unsigned int status; + + if (s->maxdata > 0x0fff) { + status = inb(dev->iobase + PCL812_STATUS_REG); + if ((status & PCL812_STATUS_DRDY) == 0) + return 0; + } else { + status = inb(dev->iobase + PCL812_AI_MSB_REG); + if ((status & PCL812_AI_MSB_DRDY) == 0) + return 0; + } + return -EBUSY; } -#endif -/* -============================================================================== -*/ 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); + struct pcl812_private *devpriv = dev->private; int err = 0; - int tmp, divisor1, divisor2; - -#ifdef PCL812_EXTDEBUG - printk("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...)\n"); - pcl812_cmdtest_out(-1, cmd); -#endif - /* step 1: make sure trigger sources are trivially valid */ + unsigned int flags; + unsigned int arg; - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); - tmp = cmd->convert_src; if (devpriv->use_ext_trg) - cmd->convert_src &= TRIG_EXT; + flags = TRIG_EXT; else - cmd->convert_src &= TRIG_TIMER; - - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) { -#ifdef PCL812_EXTDEBUG - pcl812_cmdtest_out(1, cmd); - printk - ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=1\n", - err); -#endif - return 1; - } + flags = TRIG_TIMER; + err |= cfc_check_trigger_src(&cmd->convert_src, flags); - /* - * step 2: make sure trigger sources are - * unique and mutually compatible - */ + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - if (cmd->start_src != TRIG_NOW) { - cmd->start_src = TRIG_NOW; - err++; - } + if (err) + return 1; - if (cmd->scan_begin_src != TRIG_FOLLOW) { - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } + /* Step 2a : make sure trigger sources are unique */ - if (devpriv->use_ext_trg) { - if (cmd->convert_src != TRIG_EXT) { - cmd->convert_src = TRIG_EXT; - err++; - } - } else { - if (cmd->convert_src != TRIG_TIMER) { - cmd->convert_src = TRIG_TIMER; - err++; - } - } + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } + /* Step 2b : and mutually compatible */ - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; - - if (err) { -#ifdef PCL812_EXTDEBUG - pcl812_cmdtest_out(2, cmd); - printk - ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=2\n", - err); -#endif + if (err) return 2; - } - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + board->ai_ns_min); + else /* TRIG_EXT */ + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < this_board->ai_ns_min) { - cmd->convert_arg = this_board->ai_ns_min; - err++; - } - } else { /* TRIG_EXT */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1); + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (!cmd->chanlist_len) { - cmd->chanlist_len = 1; - err++; - } - if (cmd->chanlist_len > MAX_CHANLIST_LEN) { - cmd->chanlist_len = this_board->n_aichan; - err++; - } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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) { -#ifdef PCL812_EXTDEBUG - pcl812_cmdtest_out(3, cmd); - printk - ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=3\n", - err); -#endif + if (err) return 3; - } /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_2MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } - if (err) { -#ifdef PCL812_EXTDEBUG - printk - ("pcl812 EDBG: BGN: pcl812_ai_cmdtest(...) err=%d ret=4\n", - err); -#endif + if (err) return 4; - } return 0; } -/* -============================================================================== -*/ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned int divisor1 = 0, divisor2 = 0, i, dma_flags, bytes; + struct pcl812_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl = 0; + unsigned int i; -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cmd(...)\n"); -#endif - - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (devpriv->use_ext_trg) { - if (cmd->convert_src != TRIG_EXT) - return -EINVAL; - } else { - if (cmd->convert_src != TRIG_TIMER) - return -EINVAL; - } - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; - if (cmd->chanlist_len > MAX_CHANLIST_LEN) - return -EINVAL; - - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; - i8253_cascade_ns_to_timer(this_board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl812_start_pacer(dev, false); - devpriv->ai_n_chan = cmd->chanlist_len; - memcpy(devpriv->ai_chanlist, cmd->chanlist, - sizeof(unsigned int) * cmd->scan_end_arg); - /* select first channel and range */ - setup_range_channel(dev, s, devpriv->ai_chanlist[0], 1); + pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1); if (devpriv->dma) { /* check if we can use DMA transfer */ devpriv->ai_dma = 1; - for (i = 1; i < devpriv->ai_n_chan; i++) - if (devpriv->ai_chanlist[0] != devpriv->ai_chanlist[i]) { + for (i = 1; i < cmd->chanlist_len; i++) + if (cmd->chanlist[0] != cmd->chanlist[i]) { /* we cann't use DMA :-( */ devpriv->ai_dma = 0; break; } - } else - devpriv->ai_dma = 0; - - devpriv->ai_flags = cmd->flags; - devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; + devpriv->ai_dma = 0; } devpriv->ai_act_scan = 0; @@ -894,273 +813,140 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) s->async->cur_chan = 0; /* don't we want wake up every scan? */ - if ((devpriv->ai_flags & TRIG_WAKE_EOS)) { + if (cmd->flags & TRIG_WAKE_EOS) { devpriv->ai_eos = 1; /* DMA is useless for this situation */ - if (devpriv->ai_n_chan == 1) + if (cmd->chanlist_len == 1) devpriv->ai_dma = 0; } - if (devpriv->ai_dma) { - /* we use EOS, so adapt DMA buffer to one scan */ - if (devpriv->ai_eos) { - devpriv->dmabytestomove[0] = - devpriv->ai_n_chan * sizeof(short); - devpriv->dmabytestomove[1] = - devpriv->ai_n_chan * sizeof(short); - devpriv->dma_runs_to_end = 1; - } else { - devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; - devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; - if (devpriv->ai_data_len < devpriv->hwdmasize[0]) - devpriv->dmabytestomove[0] = - devpriv->ai_data_len; - if (devpriv->ai_data_len < devpriv->hwdmasize[1]) - devpriv->dmabytestomove[1] = - devpriv->ai_data_len; - if (devpriv->ai_neverending) { - devpriv->dma_runs_to_end = 1; - } else { - /* how many samples we must transfer? */ - bytes = devpriv->ai_n_chan * - devpriv->ai_scans * sizeof(short); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = - bytes / devpriv->dmabytestomove[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = - bytes % devpriv->dmabytestomove[0]; - if (devpriv->dma_runs_to_end == 0) - devpriv->dmabytestomove[0] = - devpriv->last_dma_run; - devpriv->dma_runs_to_end--; - } - } - if (devpriv->dmabytestomove[0] > devpriv->hwdmasize[0]) { - devpriv->dmabytestomove[0] = devpriv->hwdmasize[0]; - devpriv->ai_eos = 0; - } - if (devpriv->dmabytestomove[1] > devpriv->hwdmasize[1]) { - devpriv->dmabytestomove[1] = devpriv->hwdmasize[1]; - devpriv->ai_eos = 0; - } - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); -#ifdef PCL812_EXTDEBUG - printk - ("pcl812 EDBG: DMA %d PTR 0x%0x/0x%0x LEN %u/%u EOS %d\n", - devpriv->dma, devpriv->hwdmaptr[0], - devpriv->hwdmaptr[1], devpriv->dmabytestomove[0], - devpriv->dmabytestomove[1], devpriv->ai_eos); -#endif - } + if (devpriv->ai_dma) + pcl812_ai_setup_dma(dev, s); switch (cmd->convert_src) { case TRIG_TIMER: - start_pacer(dev, 1, divisor1, divisor2); + pcl812_start_pacer(dev, true); break; } - if (devpriv->ai_dma) /* let's go! */ - outb(devpriv->mode_reg_int | 2, dev->iobase + PCL812_MODE); - else /* let's go! */ - outb(devpriv->mode_reg_int | 6, dev->iobase + PCL812_MODE); - -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cmd(...)\n"); -#endif + if (devpriv->ai_dma) + ctrl |= PCL812_CTRL_PACER_DMA_TRIG; + else + ctrl |= PCL812_CTRL_PACER_EOC_TRIG; + outb(devpriv->mode_reg_int | ctrl, dev->iobase + PCL812_CTRL_REG); return 0; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) +static bool pcl812_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) { - char err = 1; - unsigned int mask, timeout; - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - unsigned int next_chan; + struct pcl812_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - s->async->events = 0; + s->async->events |= COMEDI_CB_BLOCK; - timeout = 50; /* wait max 50us, it must finish under 33us */ - if (devpriv->ai_is16b) { - mask = 0xffff; - while (timeout--) { - if (!(inb(dev->iobase + ACL8216_STATUS) & ACL8216_DRDY)) { - err = 0; - break; - } - udelay(1); - } - } else { - mask = 0x0fff; - while (timeout--) { - if (!(inb(dev->iobase + PCL812_AD_HI) & PCL812_DRDY)) { - err = 0; - break; - } - udelay(1); - } + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; } - if (err) { - printk - ("comedi%d: pcl812: (%s at 0x%lx) " - "A/D cmd IRQ without DRDY!\n", - dev->minor, dev->board_name, dev->iobase); - pcl812_ai_cancel(dev, s); + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; + } + + return true; +} + +static void pcl812_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int next_chan; + + if (pcl812_ai_eoc(dev, s, NULL, 0)) { + dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n"); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + return; } - comedi_buf_put(s->async, - ((inb(dev->iobase + PCL812_AD_HI) << 8) | - inb(dev->iobase + PCL812_AD_LO)) & mask); + comedi_buf_put(s, pcl812_ai_get_sample(dev, s)); /* Set up next channel. Added by abbotti 2010-01-20, but untested. */ next_chan = s->async->cur_chan + 1; - if (next_chan >= devpriv->ai_n_chan) + if (next_chan >= cmd->chanlist_len) next_chan = 0; - if (devpriv->ai_chanlist[s->async->cur_chan] != - devpriv->ai_chanlist[next_chan]) - setup_range_channel(dev, s, devpriv->ai_chanlist[next_chan], 0); - - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ + if (cmd->chanlist[s->async->cur_chan] != cmd->chanlist[next_chan]) + pcl812_ai_set_chan_range(dev, cmd->chanlist[next_chan], 0); - s->async->cur_chan = next_chan; - if (next_chan == 0) { /* one scan done */ - devpriv->ai_act_scan++; - if (!(devpriv->ai_neverending)) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - } - - comedi_event(dev, s); - return IRQ_HANDLED; + pcl812_ai_next_chan(dev, s); } -/* -============================================================================== -*/ static void transfer_from_dma_buf(struct comedi_device *dev, - struct comedi_subdevice *s, short *ptr, + struct comedi_subdevice *s, + unsigned short *ptr, unsigned int bufptr, unsigned int len) { unsigned int i; - s->async->events = 0; for (i = len; i; i--) { - /* get one sample */ - comedi_buf_put(s->async, ptr[bufptr++]); - - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl812_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - break; - } - } - } + comedi_buf_put(s, ptr[bufptr++]); - comedi_event(dev, s); + if (!pcl812_ai_next_chan(dev, s)) + break; + } } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) +static void pcl812_handle_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - unsigned long dma_flags; + struct pcl812_private *devpriv = dev->private; int len, bufptr; - short *ptr; + unsigned short *ptr; -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: BGN: interrupt_pcl812_ai_dma(...)\n"); -#endif - ptr = (short *)devpriv->dmabuf[devpriv->next_dma_buf]; + ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) - devpriv->ai_poll_ptr; - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - disable_dma(devpriv->dma); - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->ai_eos) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv->next_dma_buf]); - } else { - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->dmabytestomove[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - devpriv->dma_runs_to_end--; - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ + pcl812_ai_setup_next_dma(dev, s); bufptr = devpriv->ai_poll_ptr; devpriv->ai_poll_ptr = 0; transfer_from_dma_buf(dev, s, ptr, bufptr, len); - -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: END: interrupt_pcl812_ai_dma(...)\n"); -#endif - return IRQ_HANDLED; } -/* -============================================================================== -*/ -static irqreturn_t interrupt_pcl812(int irq, void *d) +static irqreturn_t pcl812_interrupt(int irq, void *d) { struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct pcl812_private *devpriv = dev->private; if (!dev->attached) { - comedi_error(dev, "spurious interrupt"); + pcl812_ai_clear_eoc(dev); return IRQ_HANDLED; } + if (devpriv->ai_dma) - return interrupt_pcl812_ai_dma(irq, d); + pcl812_handle_dma(dev, s); else - return interrupt_pcl812_ai_int(irq, d); + pcl812_handle_eoc(dev, s); + + pcl812_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcl812_private *devpriv = dev->private; unsigned long flags; unsigned int top1, top2, i; @@ -1202,431 +988,357 @@ static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== -*/ -static void setup_range_channel(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int rangechan, char wait) +static int pcl812_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) { - unsigned char chan_reg = CR_CHAN(rangechan); /* normal board */ - /* gain index */ - unsigned char gain_reg = CR_RANGE(rangechan) + - devpriv->range_correction; + struct pcl812_private *devpriv = dev->private; - if ((chan_reg == devpriv->old_chan_reg) - && (gain_reg == devpriv->old_gain_reg)) - return; /* we can return, no change */ + if (devpriv->ai_dma) + disable_dma(devpriv->dma); - devpriv->old_chan_reg = chan_reg; - devpriv->old_gain_reg = gain_reg; + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_start_pacer(dev, false); + pcl812_ai_clear_eoc(dev); + return 0; +} - if (devpriv->use_MPC) { - if (devpriv->use_diff) { - chan_reg = chan_reg | 0x30; /* DIFF inputs */ - } else { - if (chan_reg & 0x80) - /* SE inputs 8-15 */ - chan_reg = chan_reg | 0x20; - else - /* SE inputs 0-7 */ - chan_reg = chan_reg | 0x10; - } - } +static int pcl812_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcl812_private *devpriv = dev->private; + int ret = 0; + int i; - outb(chan_reg, dev->iobase + PCL812_MUX); /* select channel */ - outb(gain_reg, dev->iobase + PCL812_GAIN); /* select gain */ + outb(devpriv->mode_reg_int | PCL812_CTRL_SOFT_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_set_chan_range(dev, insn->chanspec, 1); - if (wait) - /* - * XXX this depends on selected range and can be very long for - * some high gain ranges! - */ - udelay(devpriv->max_812_ai_mode0_rangewait); + for (i = 0; i < insn->n; i++) { + pcl812_ai_clear_eoc(dev); + pcl812_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl812_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl812_ai_get_sample(dev, s); + } + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_clear_eoc(dev); + + return ret ? ret : insn->n; } -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) +static int pcl812_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, - divisor1, divisor2); -#endif - outb(0xb4, dev->iobase + PCL812_CTRCTL); - outb(0x74, dev->iobase + PCL812_CTRCTL); - udelay(1); + struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL812_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL812_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL812_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL812_CTR1); + for (i = 0; i < insn->n; i++) { + outb((data[i] & 0xff), + dev->iobase + PCL812_AO_LSB_REG(chan)); + outb((data[i] >> 8) & 0x0f, + dev->iobase + PCL812_AO_MSB_REG(chan)); + devpriv->ao_readback[chan] = data[i]; } -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: END: start_pacer(...)\n"); -#endif + + return insn->n; } -/* -============================================================================== -*/ -static void free_resources(struct comedi_device *dev) +static int pcl812_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct pcl812_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - if (dev->private) { - if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); - if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); - if (devpriv->dma) - free_dma(devpriv->dma); - } - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, this_board->io_range); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; } -/* -============================================================================== -*/ -static int pcl812_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) +static int pcl812_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_ai_cancel(...)\n"); -#endif - if (devpriv->ai_dma) - disable_dma(devpriv->dma); - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ - /* Stop A/D */ - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - start_pacer(dev, -1, 0, 0); /* stop 8254 */ - outb(0, dev->iobase + PCL812_CLRINT); /* clear INT request */ -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_ai_cancel(...)\n"); -#endif - return 0; + data[1] = inb(dev->iobase + PCL812_DI_LSB_REG) | + (inb(dev->iobase + PCL812_DI_MSB_REG) << 8); + + return insn->n; +} + +static int pcl812_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL812_DO_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL812_DO_MSB_REG); + } + + data[1] = s->state; + + return insn->n; } -/* -============================================================================== -*/ static void pcl812_reset(struct comedi_device *dev) { -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: BGN: pcl812_reset(...)\n"); -#endif - outb(0, dev->iobase + PCL812_MUX); - outb(0 + devpriv->range_correction, dev->iobase + PCL812_GAIN); - devpriv->old_chan_reg = -1; /* invalidate chain/gain memory */ - devpriv->old_gain_reg = -1; - - switch (this_board->board_type) { + const struct pcl812_board *board = comedi_board(dev); + struct pcl812_private *devpriv = dev->private; + unsigned int chan; + + /* disable analog input trigger */ + outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG, + dev->iobase + PCL812_CTRL_REG); + pcl812_ai_clear_eoc(dev); + + /* stop pacer */ + if (board->IRQbits) + pcl812_start_pacer(dev, false); + + /* + * Invalidate last_ai_chanspec then set analog input to + * known channel/range. + */ + devpriv->last_ai_chanspec = CR_PACK(16, 0, 0); + pcl812_ai_set_chan_range(dev, CR_PACK(0, 0, 0), 0); + + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL812_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL812_AO_MSB_REG(chan)); + } + + /* set all digital outputs low */ + if (board->has_dio) { + outb(0, dev->iobase + PCL812_DO_MSB_REG); + outb(0, dev->iobase + PCL812_DO_LSB_REG); + } +} + +static void pcl812_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl812_board *board = comedi_board(dev); + struct pcl812_private *devpriv = dev->private; + + /* default to the range table from the boardinfo */ + s->range_table = board->rangelist_ai; + + /* now check the user config option based on the boardtype */ + switch (board->board_type) { case boardPCL812PG: + if (it->options[4] == 1) + s->range_table = &range_pcl812pg2_ai; + break; case boardPCL812: - case boardACL8112: - case boardACL8216: - outb(0, dev->iobase + PCL812_DA2_LO); - outb(0, dev->iobase + PCL812_DA2_HI); - case boardA821: - outb(0, dev->iobase + PCL812_DA1_LO); - outb(0, dev->iobase + PCL812_DA1_HI); - start_pacer(dev, -1, 0, 0); /* stop 8254 */ - outb(0, dev->iobase + PCL812_DO_HI); - outb(0, dev->iobase + PCL812_DO_LO); - outb(devpriv->mode_reg_int | 0, dev->iobase + PCL812_MODE); - outb(0, dev->iobase + PCL812_CLRINT); + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range812_bipolar1_25; + break; + case 4: + s->range_table = &range812_bipolar0_625; + break; + case 5: + s->range_table = &range812_bipolar0_3125; + break; + default: + s->range_table = &range_bipolar10; + break; + } break; case boardPCL813B: - case boardPCL813: + if (it->options[1] == 1) + s->range_table = &range_pcl813b2_ai; + break; case boardISO813: + switch (it->options[1]) { + case 0: + s->range_table = &range_iso813_1_ai; + break; + case 1: + s->range_table = &range_iso813_1_2_ai; + break; + case 2: + s->range_table = &range_iso813_2_ai; + devpriv->range_correction = 1; + break; + case 3: + s->range_table = &range_iso813_2_2_ai; + devpriv->range_correction = 1; + break; + default: + s->range_table = &range_iso813_1_ai; + break; + } + break; case boardACL8113: - udelay(5); + switch (it->options[1]) { + case 0: + s->range_table = &range_acl8113_1_ai; + break; + case 1: + s->range_table = &range_acl8113_1_2_ai; + break; + case 2: + s->range_table = &range_acl8113_2_ai; + devpriv->range_correction = 1; + break; + case 3: + s->range_table = &range_acl8113_2_2_ai; + devpriv->range_correction = 1; + break; + default: + s->range_table = &range_acl8113_1_ai; + break; + } break; } - udelay(5); -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "pcl812 EDBG: END: pcl812_reset(...)\n"); -#endif } -/* -============================================================================== -*/ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int ret, subdev; - unsigned long iobase; - unsigned int irq; - unsigned int dma; - unsigned long pages; + const struct pcl812_board *board = comedi_board(dev); + struct pcl812_private *devpriv; struct comedi_subdevice *s; int n_subdevices; + int subdev; + int ret; + int i; - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: pcl812: board=%s, ioport=0x%03lx", - dev->minor, this_board->name, iobase); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - if (!request_region(iobase, this_board->io_range, "pcl812")) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; - ret = alloc_private(dev, sizeof(struct pcl812_private)); - if (ret < 0) { - free_resources(dev); - return ret; /* Can't alloc mem */ + if ((1 << it->options[1]) & board->IRQbits) { + ret = request_irq(it->options[1], pcl812_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - dev->board_name = this_board->name; - - irq = 0; - if (this_board->IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & this_board->IRQbits) == 0) { - printk - (", IRQ %u is out of allowed range, " - "DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq - (irq, interrupt_pcl812, 0, "pcl812", dev)) { - printk - (", unable to allocate IRQ %u, " - "DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(KERN_INFO ", irq=%u", irq); - } - } - } - } - - dev->irq = irq; - - dma = 0; - devpriv->dma = dma; - if (!dev->irq) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (this_board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (((1 << dma) & this_board->DMAbits) == 0) { - printk(", DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, "pcl812"); + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); if (ret) { - printk(KERN_ERR ", unable to allocate DMA %u, FAIL!\n", - dma); - return -EBUSY; /* DMA isn't free */ - } - devpriv->dma = dma; - printk(KERN_INFO ", dma=%u", dma); - pages = 1; /* we want 8KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) { - printk(", unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - free_resources(dev); - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = PAGE_SIZE * (1 << pages); - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - printk(KERN_ERR ", unable to allocate DMA buffer, FAIL!\n"); - free_resources(dev); + dev_err(dev->class_dev, + "unable to request DMA channel %d\n", + it->options[2]); return -EBUSY; } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = PAGE_SIZE * (1 << pages); + devpriv->dma = it->options[2]; + + devpriv->dmapages = 1; /* we want 8KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); + } } -no_dma: - n_subdevices = 0; - if (this_board->n_aichan > 0) - n_subdevices++; - if (this_board->n_aochan > 0) - n_subdevices++; - if (this_board->n_dichan > 0) - n_subdevices++; - if (this_board->n_dochan > 0) + /* differential analog inputs? */ + switch (board->board_type) { + case boardA821: + if (it->options[2] == 1) + devpriv->use_diff = 1; + break; + case boardACL8112: + case boardACL8216: + if (it->options[4] == 1) + devpriv->use_diff = 1; + break; + } + + n_subdevices = 1; /* all boardtypes have analog inputs */ + if (board->n_aochan > 0) n_subdevices++; + if (board->has_dio) + n_subdevices += 2; - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) { - free_resources(dev); + ret = comedi_alloc_subdevices(dev, n_subdevices); + if (ret) return ret; - } subdev = 0; - /* analog input */ - if (this_board->n_aichan > 0) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE; - switch (this_board->board_type) { - case boardA821: - if (it->options[2] == 1) { - s->n_chan = this_board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - devpriv->use_diff = 1; - } else { - s->n_chan = this_board->n_aichan; - s->subdev_flags |= SDF_GROUND; - } - break; - case boardACL8112: - case boardACL8216: - if (it->options[4] == 1) { - s->n_chan = this_board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - devpriv->use_diff = 1; - } else { - s->n_chan = this_board->n_aichan; - s->subdev_flags |= SDF_GROUND; - } - break; - default: - s->n_chan = this_board->n_aichan; - s->subdev_flags |= SDF_GROUND; - break; - } - s->maxdata = this_board->ai_maxdata; - s->len_chanlist = MAX_CHANLIST_LEN; - s->range_table = this_board->rangelist_ai; - if (this_board->board_type == boardACL8216) - s->insn_read = acl8216_ai_insn_read; - else - s->insn_read = pcl812_ai_insn_read; - - devpriv->use_MPC = this_board->haveMPC508; - s->cancel = pcl812_ai_cancel; - if (dev->irq) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmdtest = pcl812_ai_cmdtest; - s->do_cmd = pcl812_ai_cmd; - s->poll = pcl812_ai_poll; - } - switch (this_board->board_type) { - case boardPCL812PG: - if (it->options[4] == 1) - s->range_table = &range_pcl812pg2_ai; - break; - case boardPCL812: - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range812_bipolar1_25; - break; - case 4: - s->range_table = &range812_bipolar0_625; - break; - case 5: - s->range_table = &range812_bipolar0_3125; - break; - default: - s->range_table = &range_bipolar10; - break; - printk - (", incorrect range number %d, changing " - "to 0 (+/-10V)", it->options[4]); - break; - } - break; - break; - case boardPCL813B: - if (it->options[1] == 1) - s->range_table = &range_pcl813b2_ai; - break; - case boardISO813: - switch (it->options[1]) { - case 0: - s->range_table = &range_iso813_1_ai; - break; - case 1: - s->range_table = &range_iso813_1_2_ai; - break; - case 2: - s->range_table = &range_iso813_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_iso813_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_iso813_1_ai; - break; - printk - (", incorrect range number %d, " - "changing to 0 ", it->options[1]); - break; - } - break; - case boardACL8113: - switch (it->options[1]) { - case 0: - s->range_table = &range_acl8113_1_ai; - break; - case 1: - s->range_table = &range_acl8113_1_2_ai; - break; - case 2: - s->range_table = &range_acl8113_2_ai; - devpriv->range_correction = 1; - break; - case 3: - s->range_table = &range_acl8113_2_2_ai; - devpriv->range_correction = 1; - break; - default: - s->range_table = &range_acl8113_1_ai; - break; - printk - (", incorrect range number %d, " - "changing to 0 ", it->options[1]); - break; - } - break; - } - subdev++; + /* Analog Input subdevice */ + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (devpriv->use_diff) { + s->subdev_flags |= SDF_DIFF; + s->n_chan = board->n_aichan / 2; + } else { + s->subdev_flags |= SDF_GROUND; + s->n_chan = board->n_aichan; } + s->maxdata = board->has_16bit_ai ? 0xffff : 0x0fff; + + pcl812_set_ai_range_table(dev, s, it); + + s->insn_read = pcl812_ai_insn_read; + + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = MAX_CHANLIST_LEN; + s->do_cmdtest = pcl812_ai_cmdtest; + s->do_cmd = pcl812_ai_cmd; + s->poll = pcl812_ai_poll; + s->cancel = pcl812_ai_cancel; + } + + devpriv->use_mpc508 = board->has_mpc508_mux; + + subdev++; /* analog output */ - if (this_board->n_aochan > 0) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = this_board->n_aochan; - s->maxdata = 0xfff; - s->len_chanlist = 1; - s->range_table = this_board->rangelist_ao; - s->insn_read = pcl812_ao_insn_read; - s->insn_write = pcl812_ao_insn_write; - switch (this_board->board_type) { + if (board->n_aochan > 0) { + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0xfff; + s->range_table = &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) s->range_table = &range_unipolar10; @@ -1644,35 +1356,30 @@ no_dma: subdev++; } - /* digital input */ - if (this_board->n_dichan > 0) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = this_board->n_dichan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dichan; - s->range_table = &range_digital; - s->insn_bits = pcl812_di_insn_bits; + if (board->has_dio) { + /* Digital Input subdevice */ + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_di_insn_bits; subdev++; - } - /* digital output */ - if (this_board->n_dochan > 0) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = this_board->n_dochan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dochan; - s->range_table = &range_digital; - s->insn_bits = pcl812_do_insn_bits; + /* Digital Output subdevice */ + s = &dev->subdevices[subdev]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl812_do_insn_bits; subdev++; } - switch (this_board->board_type) { + switch (board->board_type) { case boardACL8216: - devpriv->ai_is16b = 1; case boardPCL812PG: case boardPCL812: case boardACL8112: @@ -1680,9 +1387,10 @@ no_dma: if (it->options[3] > 0) /* we use external trigger */ devpriv->use_ext_trg = 1; + break; case boardA821: devpriv->max_812_ai_mode0_rangewait = 1; - devpriv->mode_reg_int = (irq << 4) & 0xf0; + devpriv->mode_reg_int = (dev->irq << 4) & 0xf0; break; case boardPCL813B: case boardPCL813: @@ -1693,27 +1401,37 @@ no_dma: break; } - printk(KERN_INFO "\n"); - devpriv->valid = 1; - pcl812_reset(dev); return 0; } -/* -============================================================================== - */ -static int pcl812_detach(struct comedi_device *dev) +static void pcl812_detach(struct comedi_device *dev) { + struct pcl812_private *devpriv = dev->private; -#ifdef PCL812_EXTDEBUG - printk(KERN_DEBUG "comedi%d: pcl812: remove\n", dev->minor); -#endif - free_resources(dev); - return 0; + if (devpriv) { + if (devpriv->dmabuf[0]) + free_pages(devpriv->dmabuf[0], devpriv->dmapages); + if (devpriv->dmabuf[1]) + free_pages(devpriv->dmabuf[1], devpriv->dmapages); + if (devpriv->dma) + free_dma(devpriv->dma); + } + comedi_legacy_detach(dev); } +static struct comedi_driver pcl812_driver = { + .driver_name = "pcl812", + .module = THIS_MODULE, + .attach = pcl812_attach, + .detach = pcl812_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl812_board), +}; +module_comedi_driver(pcl812_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index 8f3fc6ee088..d9ca7fe16c9 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -32,579 +32,382 @@ Configuration Options: */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/mc146818rtc.h> #include <linux/gfp.h> #include <linux/delay.h> +#include <linux/io.h> +#include <linux/interrupt.h> #include <asm/dma.h> +#include "comedi_fc.h" #include "8253.h" -#define DEBUG(x) x - -/* boards constants */ -/* IO space len */ -#define PCLx1x_RANGE 16 - -/* #define outb(x,y) printk("OUTB(%x, 200+%d)\n", x,y-0x200); outb(x,y) */ - -/* INTEL 8254 counters */ -#define PCL816_CTR0 4 -#define PCL816_CTR1 5 -#define PCL816_CTR2 6 -/* R: counter read-back register W: counter control */ -#define PCL816_CTRCTL 7 - -/* R: A/D high byte W: A/D range control */ -#define PCL816_RANGE 9 -/* W: clear INT request */ -#define PCL816_CLRINT 10 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL816_MUX 11 -/* R/W: operation control register */ -#define PCL816_CONTROL 12 - -/* R: return status byte W: set DMA/IRQ */ -#define PCL816_STATUS 13 -#define PCL816_STATUS_DRDY_MASK 0x80 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL816_AD_LO 8 -/* R: high byte of A/D W: A/D range control */ -#define PCL816_AD_HI 9 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 -#ifdef unused -#define INT_TYPE_AI1_DMA_RTC 9 -#define INT_TYPE_AI3_DMA_RTC 10 - -/* RTC stuff... */ -#define RTC_IRQ 8 -#define RTC_IO_EXTENT 0x10 -#endif +/* + * Register I/O map + */ +#define PCL816_DO_DI_LSB_REG 0x00 +#define PCL816_DO_DI_MSB_REG 0x01 +#define PCL816_TIMER_BASE 0x04 +#define PCL816_AI_LSB_REG 0x08 +#define PCL816_AI_MSB_REG 0x09 +#define PCL816_RANGE_REG 0x09 +#define PCL816_CLRINT_REG 0x0a +#define PCL816_MUX_REG 0x0b +#define PCL816_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL816_CTRL_REG 0x0c +#define PCL816_CTRL_DISABLE_TRIG (0 << 0) +#define PCL816_CTRL_SOFT_TRIG (1 << 0) +#define PCL816_CTRL_PACER_TRIG (1 << 1) +#define PCL816_CTRL_EXT_TRIG (1 << 2) +#define PCL816_CTRL_POE (1 << 3) +#define PCL816_CTRL_DMAEN (1 << 4) +#define PCL816_CTRL_INTEN (1 << 5) +#define PCL816_CTRL_DMASRC_SLOT0 (0 << 6) +#define PCL816_CTRL_DMASRC_SLOT1 (1 << 6) +#define PCL816_CTRL_DMASRC_SLOT2 (2 << 6) +#define PCL816_STATUS_REG 0x0d +#define PCL816_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL816_STATUS_INTSRC_MASK (3 << 4) +#define PCL816_STATUS_INTSRC_SLOT0 (0 << 4) +#define PCL816_STATUS_INTSRC_SLOT1 (1 << 4) +#define PCL816_STATUS_INTSRC_SLOT2 (2 << 4) +#define PCL816_STATUS_INTSRC_DMA (3 << 4) +#define PCL816_STATUS_INTACT (1 << 6) +#define PCL816_STATUS_DRDY (1 << 7) #define MAGIC_DMA_WORD 0x5a5a -static const struct comedi_lrange range_pcl816 = { 8, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - } +static const struct comedi_lrange range_pcl816 = { + 8, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25) + } }; struct pcl816_board { - - const char *name; /* board name */ - int n_ranges; /* len of range list */ - int n_aichan; /* num of A/D chans in diferencial mode */ - unsigned int ai_ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - int ai_chanlist; /* allowed len of channel list A/D */ - int ao_chanlist; /* allowed len of channel list D/A */ - int i8254_osc_base; /* 1/frequency of on board oscilator in ns */ + const char *name; + int ai_maxdata; + int ao_maxdata; + int ai_chanlist; }; static const struct pcl816_board boardtypes[] = { - {"pcl816", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, /* IRQ mask */ - 0x0a, /* DMA mask */ - 0xffff, /* 16-bit card */ - 0xffff, /* D/A maxdata */ - 1024, - 1, /* ao chan list */ - 100}, - {"pcl814b", 8, 16, 10000, 1, 16, 16, &range_pcl816, - &range_pcl816, PCLx1x_RANGE, - 0x00fc, - 0x0a, - 0x3fff, /* 14 bit card */ - 0x3fff, - 1024, - 1, - 100}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl816_board)) -#define devpriv ((struct pcl816_private *)dev->private) -#define this_board ((const struct pcl816_board *)dev->board_ptr) - -static int pcl816_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl816_detach(struct comedi_device *dev); - -#ifdef unused -static int RTC_lock = 0; /* RTC lock */ -static int RTC_timer_lock = 0; /* RTC int lock */ -#endif - -static struct comedi_driver driver_pcl816 = { - .driver_name = "pcl816", - .module = THIS_MODULE, - .attach = pcl816_attach, - .detach = pcl816_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl816_board), + { + .name = "pcl816", + .ai_maxdata = 0xffff, + .ao_maxdata = 0xffff, + .ai_chanlist = 1024, + }, { + .name = "pcl814b", + .ai_maxdata = 0x3fff, + .ao_maxdata = 0x3fff, + .ai_chanlist = 1024, + }, }; -static int __init driver_pcl816_init_module(void) -{ - return comedi_driver_register(&driver_pcl816); -} - -static void __exit driver_pcl816_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl816); -} - -module_init(driver_pcl816_init_module); -module_exit(driver_pcl816_cleanup_module); - struct pcl816_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ - int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */ -#ifdef unused - unsigned long rtc_iobase; /* RTC port region */ - unsigned int rtc_iosize; - unsigned int rtc_irq; -#endif + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ - unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ - unsigned int last_top_dma; /* DMA pointer in last RTC int */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - - unsigned int ai_scans; /* len of scanlist */ - unsigned char ai_neverending; /* if=1, then we do neverending record (you must use cancel()) */ - int irq_free; /* 1=have allocated IRQ */ - int irq_blocked; /* 1=IRQ now uses any subdev */ -#ifdef unused - int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */ -#endif - int irq_was_now_closed; /* when IRQ finish, there's stored int816_mode for last interrupt */ - int int816_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ - unsigned int ai_act_chanlist[16]; /* MUX setting for actual AI operations */ - unsigned int ai_act_chanlist_len; /* how long is actual MUX list */ - unsigned int ai_act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_n_chan; /* how many channels per scan */ unsigned int ai_poll_ptr; /* how many sampes transfer poll */ - struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ -#ifdef unused - struct timer_list rtc_irq_timer; /* timer for RTC sanity check */ - unsigned long rtc_freq; /* RTC int freq */ -#endif + unsigned int divisor1; + unsigned int divisor2; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -/* -============================================================================== -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int chanlen); -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int seglen); -static int pcl816_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -#ifdef unused -static int set_rtc_irq_bit(unsigned char bit); -#endif - -static int pcl816_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -/* -============================================================================== - ANALOG INPUT MODE0, 816 cards, slow version -*/ -static int pcl816_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters) { - int n; - int timeout; - - DPRINTK("mode 0 analog input\n"); - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL816_CONTROL); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Set the input channel */ - outb(CR_CHAN(insn->chanspec) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL816_RANGE); - - for (n = 0; n < insn->n; n++) { - - outb(0, dev->iobase + PCL816_AD_LO); /* start conversion */ - - timeout = 100; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) { - /* return read value */ - data[n] = - ((inb(dev->iobase + - PCL816_AD_HI) << 8) | - (inb(dev->iobase + PCL816_AD_LO))); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - break; - } - udelay(1); - } - /* Return timeout error */ - if (!timeout) { - comedi_error(dev, "A/D insn timeout\n"); - data[0] = 0; - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL816_CLRINT); - return -EIO; - } + struct pcl816_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; + + i8254_set_mode(timer_base, 0, 0, I8254_MODE1 | I8254_BINARY); + i8254_write(timer_base, 0, 0, 0x00ff); + udelay(1); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); + + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - return n; } -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) +static void pcl816_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - int low, hi; - int timeout = 50; /* wait max 50us */ + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dma_flags; + unsigned int bytes; - while (timeout--) { - if (!(inb(dev->iobase + PCL816_STATUS) & - PCL816_STATUS_DRDY_MASK)) - break; - udelay(1); - } - if (!timeout) { /* timeout, bail error */ - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + /* how many */ + bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + + /* how many DMA pages we must fill */ + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; + + /* on last dma transfer must be moved */ + devpriv->last_dma_run = bytes % devpriv->hwdmasize; + devpriv->dma_runs_to_end--; + if (devpriv->dma_runs_to_end >= 0) + bytes = devpriv->hwdmasize; + } else + devpriv->dma_runs_to_end = -1; + + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, bytes); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); +} + +static void pcl816_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned long dma_flags; + disable_dma(devpriv->dma); + if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { + /* switch dma bufs */ + devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + dma_flags = claim_dma_lock(); + set_dma_addr(devpriv->dma, + devpriv->hwdmaptr[devpriv->next_dma_buf]); + if (devpriv->dma_runs_to_end) + set_dma_count(devpriv->dma, devpriv->hwdmasize); + else + set_dma_count(devpriv->dma, devpriv->last_dma_run); + release_dma_lock(dma_flags); + enable_dma(devpriv->dma); } - /* get the sample */ - low = inb(dev->iobase + PCL816_AD_LO); - hi = inb(dev->iobase + PCL816_AD_HI); + devpriv->dma_runs_to_end--; +} - comedi_buf_put(s->async, (hi << 8) | low); +static void pcl816_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) +{ + outb(chan, dev->iobase + PCL816_MUX_REG); + outb(range, dev->iobase + PCL816_RANGE_REG); +} - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ +static void pcl816_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) +{ + outb(PCL816_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL816_MUX_REG); +} - if (++devpriv->ai_act_chanlist_pos >= devpriv->ai_act_chanlist_len) - devpriv->ai_act_chanlist_pos = 0; +static void pcl816_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) +{ + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + unsigned int i; - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); + + pcl816_ai_set_chan_range(dev, last_chan, range); } - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - /* all data sampled */ - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - comedi_event(dev, s); - return IRQ_HANDLED; + udelay(1); + + pcl816_ai_set_chan_scan(dev, first_chan, last_chan); } -/* -============================================================================== - analog input dma mode 1 & 3, 816 cards -*/ -static void transfer_from_dma_buf(struct comedi_device *dev, - struct comedi_subdevice *s, short *ptr, - unsigned int bufptr, unsigned int len) +static void pcl816_ai_clear_eoc(struct comedi_device *dev) { - int i; - - s->async->events = 0; + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL816_CLRINT_REG); +} - for (i = 0; i < len; i++) { +static void pcl816_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL816_AI_LSB_REG); +} - comedi_buf_put(s->async, ptr[bufptr++]); +static unsigned int pcl816_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned int val; - if (++devpriv->ai_act_chanlist_pos >= - devpriv->ai_act_chanlist_len) { - devpriv->ai_act_chanlist_pos = 0; - } + val = inb(dev->iobase + PCL816_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL816_AI_LSB_REG); - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan++; - } + return val & s->maxdata; +} - if (!devpriv->ai_neverending) - /* all data sampled */ - if (devpriv->ai_act_scan >= devpriv->ai_scans) { - pcl816_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_BLOCK; - break; - } - } +static int pcl816_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; - comedi_event(dev, s); + status = inb(dev->iobase + PCL816_STATUS_REG); + if ((status & PCL816_STATUS_DRDY) == 0) + return 0; + return -EBUSY; } -static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) +static bool pcl816_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - int len, bufptr, this_dma_buf; - unsigned long dma_flags; - short *ptr; + struct pcl816_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - disable_dma(devpriv->dma); - this_dma_buf = devpriv->next_dma_buf; + s->async->events |= COMEDI_CB_BLOCK; - /* switch dma bufs */ - if ((devpriv->dma_runs_to_end > -1) || devpriv->ai_neverending) { + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan++; + s->async->events |= COMEDI_CB_EOS; + } - devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); -/* clear_dma_ff (devpriv->dma); */ - set_dma_addr(devpriv->dma, - devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { - set_dma_count(devpriv->dma, devpriv->last_dma_run); - } - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); + if (cmd->stop_src == TRIG_COUNT && + devpriv->ai_act_scan >= cmd->stop_arg) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; } - devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ + return true; +} - ptr = (short *)devpriv->dmabuf[this_dma_buf]; +static void transfer_from_dma_buf(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned short *ptr, + unsigned int bufptr, unsigned int len) +{ + int i; - len = (devpriv->hwdmasize[0] >> 1) - devpriv->ai_poll_ptr; - bufptr = devpriv->ai_poll_ptr; - devpriv->ai_poll_ptr = 0; + for (i = 0; i < len; i++) { + comedi_buf_put(s, ptr[bufptr++]); - transfer_from_dma_buf(dev, s, ptr, bufptr, len); - return IRQ_HANDLED; + if (!pcl816_ai_next_chan(dev, s)) + return; + } } -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl816(int irq, void *d) +static irqreturn_t pcl816_interrupt(int irq, void *d) { struct comedi_device *dev = d; - DPRINTK("<I>"); - - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); + struct comedi_subdevice *s = dev->read_subdev; + struct pcl816_private *devpriv = dev->private; + unsigned short *ptr; + unsigned int bufptr; + unsigned int len; + + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl816_ai_clear_eoc(dev); return IRQ_HANDLED; } - switch (devpriv->int816_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl816_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl816_ai_mode13_int(irq, d); + if (devpriv->ai_cmd_canceled) { + devpriv->ai_cmd_canceled = 0; + pcl816_ai_clear_eoc(dev); + return IRQ_HANDLED; } - outb(0, dev->iobase + PCL816_CLRINT); /* clear INT request */ - if ((!dev->irq) | (!devpriv->irq_free) | (!devpriv->irq_blocked) | - (!devpriv->int816_mode)) { - if (devpriv->irq_was_now_closed) { - devpriv->irq_was_now_closed = 0; - /* comedi_error(dev,"last IRQ.."); */ - return IRQ_HANDLED; - } - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; - } - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; -} + ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf]; -/* -============================================================================== - COMMAND MODE -*/ -static void pcl816_cmdtest_out(int e, struct comedi_cmd *cmd) -{ - printk(KERN_INFO "pcl816 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, - cmd->start_src, cmd->scan_begin_src, cmd->convert_src); - printk(KERN_INFO "pcl816 e=%d startarg=%d scanarg=%d convarg=%d\n", e, - cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); - printk(KERN_INFO "pcl816 e=%d stopsrc=%x scanend=%x\n", e, - cmd->stop_src, cmd->scan_end_src); - printk(KERN_INFO "pcl816 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", - e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); + pcl816_ai_setup_next_dma(dev, s); + + len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr; + bufptr = devpriv->ai_poll_ptr; + devpriv->ai_poll_ptr = 0; + + transfer_from_dma_buf(dev, s, ptr, bufptr, len); + + pcl816_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pcl816_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + struct pcl816_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; - - DEBUG(printk(KERN_INFO "pcl816 pcl812_ai_cmdtest\n"); - pcl816_cmdtest_out(-1, cmd); - ); - - /* step 1: make sure trigger sources are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_EXT | TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) - return 1; + unsigned int arg; + /* Step 1 : check if triggers are trivially valid */ - /* - * step 2: make sure trigger sources - * are unique and mutually compatible - */ + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_EXT | TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - if (cmd->start_src != TRIG_NOW) { - cmd->start_src = TRIG_NOW; - err++; - } - - if (cmd->scan_begin_src != TRIG_FOLLOW) { - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } + if (err) + return 1; - if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) { - cmd->convert_src = TRIG_TIMER; - err++; - } + /* Step 2a : make sure trigger sources are unique */ - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + /* Step 3: check if arguments are trivially valid */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < this_board->ai_ns_min) { - cmd->convert_arg = this_board->ai_ns_min; - err++; - } - } else { /* TRIG_EXT */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); + else /* TRIG_EXT */ + 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) + 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; @@ -612,15 +415,12 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(this_board->i8254_osc_base, - &divisor1, &divisor2, - &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -640,140 +440,50 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned int divisor1 = 0, divisor2 = 0, dma_flags, bytes, dmairq; + struct pcl816_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; + unsigned int ctrl; unsigned int seglen; - if (cmd->start_src != TRIG_NOW) - return -EINVAL; - if (cmd->scan_begin_src != TRIG_FOLLOW) - return -EINVAL; - if (cmd->scan_end_src != TRIG_COUNT) - return -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) - return -EINVAL; -/* if(cmd->chanlist_len>MAX_CHANLIST_LEN) return -EINVAL; */ - if (devpriv->irq_blocked) + if (devpriv->ai_cmd_running) return -EBUSY; - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < this_board->ai_ns_min) - cmd->convert_arg = this_board->ai_ns_min; - - i8253_cascade_ns_to_timer(this_board->i8254_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - - /* PCL816 crash if any divisor is set to 1 */ - if (divisor1 == 1) { - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } - - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl816_start_pacer(dev, false); seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); if (seglen < 1) return -EINVAL; - setup_channel_list(dev, s, cmd->chanlist, seglen); + pcl816_ai_setup_chanlist(dev, cmd->chanlist, seglen); udelay(1); - devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_act_scan = 0; s->async->cur_chan = 0; - devpriv->irq_blocked = 1; + devpriv->ai_cmd_running = 1; devpriv->ai_poll_ptr = 0; - devpriv->irq_was_now_closed = 0; - - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; - devpriv->ai_neverending = 0; - } else { - devpriv->ai_scans = 0; - devpriv->ai_neverending = 1; - } - - /* don't we want wake up every scan? */ - if ((cmd->flags & TRIG_WAKE_EOS)) { - printk(KERN_INFO - "pl816: You wankt WAKE_EOS but I dont want handle it"); - /* devpriv->ai_eos=1; */ - /* if (devpriv->ai_n_chan==1) */ - /* devpriv->dma=0; // DMA is useless for this situation */ - } + devpriv->ai_cmd_canceled = 0; - if (devpriv->dma) { - bytes = devpriv->hwdmasize[0]; - if (!devpriv->ai_neverending) { - /* how many */ - bytes = s->async->cmd.chanlist_len * - s->async->cmd.chanlist_len * - sizeof(short); - - /* how many DMA pages we must fill */ - devpriv->dma_runs_to_end = bytes / - devpriv->hwdmasize[0]; - - /* on last dma transfer must be moved */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; - } else - devpriv->dma_runs_to_end = -1; - - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - dma_flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(dma_flags); - enable_dma(devpriv->dma); - } - - start_pacer(dev, 1, divisor1, divisor2); - dmairq = ((devpriv->dma & 0x3) << 4) | (dev->irq & 0x7); - - switch (cmd->convert_src) { - case TRIG_TIMER: - devpriv->int816_mode = INT_TYPE_AI1_DMA; + pcl816_ai_setup_dma(dev, s); - /* Pacer+IRQ+DMA */ - outb(0x32, dev->iobase + PCL816_CONTROL); + pcl816_start_pacer(dev, true); - /* write irq and DMA to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; + ctrl = PCL816_CTRL_INTEN | PCL816_CTRL_DMAEN | PCL816_CTRL_DMASRC_SLOT0; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL816_CTRL_PACER_TRIG; + else /* TRIG_EXT */ + ctrl |= PCL816_CTRL_EXT_TRIG; - default: - devpriv->int816_mode = INT_TYPE_AI3_DMA; + outb(ctrl, dev->iobase + PCL816_CTRL_REG); + outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG); - /* Ext trig+IRQ+DMA */ - outb(0x34, dev->iobase + PCL816_CONTROL); - - /* write irq to card */ - outb(dmairq, dev->iobase + PCL816_STATUS); - break; - } - - DPRINTK("pcl816 END: pcl812_ai_cmd()\n"); return 0; } static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcl816_private *devpriv = dev->private; unsigned long flags; unsigned int top1, top2, i; - if (!devpriv->dma) - return 0; /* poll is valid only for DMA transfer */ - spin_lock_irqsave(&dev->spinlock, flags); for (i = 0; i < 20; i++) { @@ -788,7 +498,7 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) } /* where is now DMA in buffer */ - top1 = devpriv->hwdmasize[0] - top1; + top1 = devpriv->hwdmasize - top1; top1 >>= 1; /* sample position */ top2 = top1 - devpriv->ai_poll_ptr; if (top2 < 1) { /* no new samples */ @@ -797,148 +507,41 @@ static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) } transfer_from_dma_buf(dev, s, - (short *)devpriv->dmabuf[devpriv->next_dma_buf], + (unsigned short *)devpriv->dmabuf[devpriv-> + next_dma_buf], devpriv->ai_poll_ptr, top2); devpriv->ai_poll_ptr = top1; /* new buffer position */ spin_unlock_irqrestore(&dev->spinlock, flags); + cfc_handle_events(dev, s); + return s->async->buf_write_count - s->async->buf_read_count; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl816_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { -/* DEBUG(printk("pcl816_ai_cancel()\n");) */ - - if (devpriv->irq_blocked > 0) { - switch (devpriv->int816_mode) { -#ifdef unused - case INT_TYPE_AI1_DMA_RTC: - case INT_TYPE_AI3_DMA_RTC: - set_rtc_irq_bit(0); /* stop RTC */ - del_timer(&devpriv->rtc_irq_timer); -#endif - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - outb(inb(dev->iobase + PCL816_CONTROL) & 0x73, - dev->iobase + PCL816_CONTROL); /* Stop A/D */ - udelay(1); - outb(0, dev->iobase + PCL816_CONTROL); /* Stop A/D */ - - /* Stop pacer */ - outb(0xb0, dev->iobase + PCL816_CTRCTL); - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_LO); - inb(dev->iobase + PCL816_AD_HI); - - /* clear INT request */ - outb(0, dev->iobase + PCL816_CLRINT); - - /* Stop A/D */ - outb(0, dev->iobase + PCL816_CONTROL); - devpriv->irq_blocked = 0; - devpriv->irq_was_now_closed = devpriv->int816_mode; - devpriv->int816_mode = 0; - devpriv->last_int_sub = s; -/* s->busy = 0; */ - break; - } - } - - DEBUG(printk("comedi: pcl816_ai_cancel() successful\n");) - return 0; -} - -/* -============================================================================== - chech for PCL816 -*/ -static int pcl816_check(unsigned long iobase) -{ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL816_MUX); - udelay(1); - if (inb(iobase + PCL816_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL816_MUX); - udelay(1); - outb(0x18, iobase + PCL816_CONTROL); - udelay(1); - if (inb(iobase + PCL816_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ -} + struct pcl816_private *devpriv = dev->private; -/* -============================================================================== - reset whole PCL-816 cards -*/ -static void pcl816_reset(struct comedi_device *dev) -{ -/* outb (0, dev->iobase + PCL818_DA_LO); DAC=0V */ -/* outb (0, dev->iobase + PCL818_DA_HI); */ -/* udelay (1); */ -/* outb (0, dev->iobase + PCL818_DO_HI); DO=$0000 */ -/* outb (0, dev->iobase + PCL818_DO_LO); */ -/* udelay (1); */ - outb(0, dev->iobase + PCL816_CONTROL); - outb(0, dev->iobase + PCL816_MUX); - outb(0, dev->iobase + PCL816_CLRINT); - outb(0xb0, dev->iobase + PCL816_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL816_CTRCTL); - outb(0x30, dev->iobase + PCL816_CTRCTL); - outb(0, dev->iobase + PCL816_RANGE); -} + if (!devpriv->ai_cmd_running) + return 0; -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void -start_pacer(struct comedi_device *dev, int mode, unsigned int divisor1, - unsigned int divisor2) -{ - outb(0x32, dev->iobase + PCL816_CTRCTL); - outb(0xff, dev->iobase + PCL816_CTR0); - outb(0x00, dev->iobase + PCL816_CTR0); - udelay(1); + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - /* set counter 2 as mode 3 */ - outb(0xb4, dev->iobase + PCL816_CTRCTL); - /* set counter 1 as mode 3 */ - outb(0x74, dev->iobase + PCL816_CTRCTL); - udelay(1); + /* Stop pacer */ + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(dev->iobase + PCL816_TIMER_BASE, 0, + 1, I8254_MODE0 | I8254_BINARY); - if (mode == 1) { - DPRINTK("mode %d, divisor1 %d, divisor2 %d\n", mode, divisor1, - divisor2); - outb(divisor2 & 0xff, dev->iobase + PCL816_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL816_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL816_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL816_CTR1); - } + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 1; - /* clear pending interrupts (just in case) */ -/* outb(0, dev->iobase + PCL816_CLRINT); */ + return 0; } -/* -============================================================================== - Check if channel list from user is builded correctly - If it's ok, then return non-zero length of repeated segment of channel list -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, @@ -957,11 +560,6 @@ check_channel_list(struct comedi_device *dev, /* first channel is every time ok */ chansegment[0] = chanlist[0]; for (i = 1, seglen = 1; i < chanlen; i++, seglen++) { - /* build part of chanlist */ - DEBUG(printk(KERN_INFO "%d. %d %d\n", i, - CR_CHAN(chanlist[i]), - CR_RANGE(chanlist[i]));) - /* we detect loop, this must by finish */ if (chanlist[0] == chanlist[i]) break; @@ -969,12 +567,10 @@ check_channel_list(struct comedi_device *dev, (CR_CHAN(chansegment[i - 1]) + 1) % chanlen; if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */ - printk(KERN_WARNING - "comedi%d: pcl816: channel list must " - "be continuous! chanlist[%i]=%d but " - "must be %d or %d!\n", dev->minor, - i, CR_CHAN(chanlist[i]), nowmustbechan, - CR_CHAN(chanlist[0])); + dev_dbg(dev->class_dev, + "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", + i, CR_CHAN(chanlist[i]), nowmustbechan, + CR_CHAN(chanlist[0])); return 0; } /* well, this is next correct channel in list */ @@ -983,22 +579,15 @@ check_channel_list(struct comedi_device *dev, /* check whole chanlist */ for (i = 0, segpos = 0; i < chanlen; i++) { - DEBUG(printk("%d %d=%d %d\n", - CR_CHAN(chansegment[i % seglen]), - CR_RANGE(chansegment[i % seglen]), - CR_CHAN(chanlist[i]), - CR_RANGE(chanlist[i]));) if (chanlist[i] != chansegment[i % seglen]) { - printk(KERN_WARNING - "comedi%d: pcl816: bad channel or range" - " number! chanlist[%i]=%d,%d,%d and not" - " %d,%d,%d!\n", dev->minor, i, - CR_CHAN(chansegment[i]), - CR_RANGE(chansegment[i]), - CR_AREF(chansegment[i]), - CR_CHAN(chanlist[i % seglen]), - CR_RANGE(chanlist[i % seglen]), - CR_AREF(chansegment[i % seglen])); + dev_dbg(dev->class_dev, + "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", + i, CR_CHAN(chansegment[i]), + CR_RANGE(chansegment[i]), + CR_AREF(chansegment[i]), + CR_CHAN(chanlist[i % seglen]), + CR_RANGE(chanlist[i % seglen]), + CR_AREF(chansegment[i % seglen])); return 0; /* chan/gain list is strange */ } } @@ -1009,351 +598,214 @@ check_channel_list(struct comedi_device *dev, return seglen; /* we can serve this with MUX logic */ } -/* -============================================================================== - Program scan/gain logic with channel list. -*/ -static void -setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int *chanlist, - unsigned int seglen) +static int pcl816_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int i; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; + + outb(PCL816_CTRL_SOFT_TRIG, dev->iobase + PCL816_CTRL_REG); - devpriv->ai_act_chanlist_len = seglen; - devpriv->ai_act_chanlist_pos = 0; + pcl816_ai_set_chan_range(dev, chan, range); + pcl816_ai_set_chan_scan(dev, chan, chan); - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->ai_act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(CR_CHAN(chanlist[0]) & 0xf, dev->iobase + PCL816_MUX); - /* select gain */ - outb(CR_RANGE(chanlist[0]), dev->iobase + PCL816_RANGE); + for (i = 0; i < insn->n; i++) { + pcl816_ai_clear_eoc(dev); + pcl816_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl816_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl816_ai_get_sample(dev, s); } + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_clear_eoc(dev); - udelay(1); - /* select channel interval to scan */ - outb(devpriv->ai_act_chanlist[0] | - (devpriv->ai_act_chanlist[seglen - 1] << 4), - dev->iobase + PCL816_MUX); + return ret ? ret : insn->n; } -#ifdef unused -/* -============================================================================== - Enable(1)/disable(0) periodic interrupts from RTC -*/ -static int set_rtc_irq_bit(unsigned char bit) +static int pcl816_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned char val; - unsigned long flags; - - if (bit == 1) { - RTC_timer_lock++; - if (RTC_timer_lock > 1) - return 0; - } else { - RTC_timer_lock--; - if (RTC_timer_lock < 0) - RTC_timer_lock = 0; - if (RTC_timer_lock > 0) - return 0; - } + data[1] = inb(dev->iobase + PCL816_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL816_DO_DI_MSB_REG) << 8); - save_flags(flags); - cli(); - val = CMOS_READ(RTC_CONTROL); - if (bit) - val |= RTC_PIE; - else - val &= ~RTC_PIE; - - CMOS_WRITE(val, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); - return 0; + return insn->n; } -#endif -/* -============================================================================== - Free any resources that we have claimed -*/ -static void free_resources(struct comedi_device *dev) +static int pcl816_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* printk("free_resource()\n"); */ - if (dev->private) { - pcl816_ai_cancel(dev, devpriv->sub_ai); - pcl816_reset(dev); - if (devpriv->dma) - free_dma(devpriv->dma); - if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); - if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); -#ifdef unused - if (devpriv->rtc_irq) - free_irq(devpriv->rtc_irq, dev); - if ((devpriv->dma_rtc) && (RTC_lock == 1)) { - if (devpriv->rtc_iobase) - release_region(devpriv->rtc_iobase, - devpriv->rtc_iosize); - } -#endif + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL816_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL816_DO_DI_MSB_REG); } - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, this_board->io_range); - /* printk("free_resource() end\n"); */ + data[1] = s->state; + + return insn->n; } -/* -============================================================================== +static void pcl816_reset(struct comedi_device *dev) +{ + unsigned long timer_base = dev->iobase + PCL816_TIMER_BASE; - Initialization + outb(PCL816_CTRL_DISABLE_TRIG, dev->iobase + PCL816_CTRL_REG); + pcl816_ai_set_chan_range(dev, 0, 0); + pcl816_ai_clear_eoc(dev); + + /* Stop pacer */ + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); + + /* set all digital outputs low */ + outb(0, dev->iobase + PCL816_DO_DI_LSB_REG); + outb(0, dev->iobase + PCL816_DO_DI_MSB_REG); +} -*/ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int ret; - unsigned long iobase; - unsigned int irq, dma; - unsigned long pages; - /* int i; */ + const struct pcl816_board *board = comedi_board(dev); + struct pcl816_private *devpriv; struct comedi_subdevice *s; + int ret; + int i; - /* claim our I/O space */ - iobase = it->options[0]; - printk("comedi%d: pcl816: board=%s, ioport=0x%03lx", dev->minor, - this_board->name, iobase); - - if (!request_region(iobase, this_board->io_range, "pcl816")) { - printk("I/O port conflict\n"); - return -EIO; - } + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - dev->iobase = iobase; + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; - if (pcl816_check(iobase)) { - printk(KERN_ERR ", I cann't detect board. FAIL!\n"); - return -EIO; + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl816_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; } - ret = alloc_private(dev, sizeof(struct pcl816_private)); - if (ret < 0) - return ret; /* Can't alloc mem */ - - /* set up some name stuff */ - dev->board_name = this_board->name; - - /* grab our IRQ */ - irq = 0; - if (this_board->IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & this_board->IRQbits) == 0) { - printk - (", IRQ %u is out of allowed range, " - "DISABLING IT", irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq - (irq, interrupt_pcl816, 0, "pcl816", dev)) { - printk - (", unable to allocate IRQ %u, " - "DISABLING IT", irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(KERN_INFO ", irq=%u", irq); - } - } + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); + if (ret) { + dev_err(dev->class_dev, + "unable to request DMA channel %d\n", + it->options[2]); + return -EBUSY; } - } + devpriv->dma = it->options[2]; - dev->irq = irq; - if (irq) /* 1=we have allocated irq */ - devpriv->irq_free = 1; - else - devpriv->irq_free = 0; - - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->int816_mode = 0; /* mode of irq */ - -#ifdef unused - /* grab RTC for DMA operations */ - devpriv->dma_rtc = 0; - if (it->options[2] > 0) { /* we want to use DMA */ - if (RTC_lock == 0) { - if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, - "pcl816 (RTC)")) - goto no_rtc; - } - devpriv->rtc_iobase = RTC_PORT(0); - devpriv->rtc_iosize = RTC_IO_EXTENT; - RTC_lock++; -#ifdef UNTESTED_CODE - if (!request_irq(RTC_IRQ, interrupt_pcl816_ai_mode13_dma_rtc, 0, - "pcl816 DMA (RTC)", dev)) { - devpriv->dma_rtc = 1; - devpriv->rtc_irq = RTC_IRQ; - printk(", dma_irq=%u", devpriv->rtc_irq); - } else { - RTC_lock--; - if (RTC_lock == 0) { - if (devpriv->rtc_iobase) - release_region(devpriv->rtc_iobase, - devpriv->rtc_iosize); - } - devpriv->rtc_iobase = 0; - devpriv->rtc_iosize = 0; - } -#else - printk("pcl816: RTC code missing"); -#endif + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; - } + for (i = 0; i < 2; i++) { + unsigned long dmabuf; -no_rtc: -#endif - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0)) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - - if (this_board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - - if (((1 << dma) & this_board->DMAbits) == 0) { - printk(", DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, "pcl816"); - if (ret) { - printk(KERN_ERR - ", unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ - } + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; - devpriv->dma = dma; - printk(KERN_INFO ", dma=%u", dma); - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - - if (!devpriv->dmabuf[0]) { - printk(", unable to allocate DMA buffer, FAIL!\n"); - /* - * maybe experiment with try_to_free_pages() - * will help .... - */ - return -EBUSY; /* no buffer :-( */ - } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ - - if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */ - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - printk(KERN_ERR - ", unable to allocate DMA buffer, " - "FAIL!\n"); - return -EBUSY; - } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = - virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); } } -no_dma: - -/* if (this_board->n_aochan > 0) - subdevs[1] = COMEDI_SUBD_AO; - if (this_board->n_dichan > 0) - subdevs[2] = COMEDI_SUBD_DI; - if (this_board->n_dochan > 0) - subdevs[3] = COMEDI_SUBD_DO; -*/ - - ret = alloc_subdevices(dev, 1); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - s = dev->subdevices + 0; - if (this_board->n_aichan > 0) { - s->type = COMEDI_SUBD_AI; - devpriv->sub_ai = s; + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_CMD_READ | SDF_DIFF; + s->n_chan = 16; + s->maxdata = board->ai_maxdata; + s->range_table = &range_pcl816; + s->insn_read = pcl816_ai_insn_read; + if (devpriv->dma) { dev->read_subdev = s; - s->subdev_flags = SDF_READABLE | SDF_CMD_READ; - s->n_chan = this_board->n_aichan; - s->subdev_flags |= SDF_DIFF; - /* printk (", %dchans DIFF DAC - %d", s->n_chan, i); */ - s->maxdata = this_board->ai_maxdata; - s->len_chanlist = this_board->ai_chanlist; - s->range_table = this_board->ai_range_type; - s->cancel = pcl816_ai_cancel; - s->do_cmdtest = pcl816_ai_cmdtest; - s->do_cmd = pcl816_ai_cmd; - s->poll = pcl816_ai_poll; - s->insn_read = pcl816_ai_insn_read; - } else { - s->type = COMEDI_SUBD_UNUSED; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = board->ai_chanlist; + s->do_cmdtest = pcl816_ai_cmdtest; + s->do_cmd = pcl816_ai_cmd; + s->poll = pcl816_ai_poll; + s->cancel = pcl816_ai_cancel; } + /* Analog OUtput subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_UNUSED; #if 0 -case COMEDI_SUBD_AO: + subdevs[1] = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = this_board->n_aochan; - s->maxdata = this_board->ao_maxdata; - s->len_chanlist = this_board->ao_chanlist; - s->range_table = this_board->ao_range_type; - break; - -case COMEDI_SUBD_DI: - s->subdev_flags = SDF_READABLE; - s->n_chan = this_board->n_dichan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dichan; - s->range_table = &range_digital; - break; - -case COMEDI_SUBD_DO: - s->subdev_flags = SDF_WRITABLE; - s->n_chan = this_board->n_dochan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dochan; - s->range_table = &range_digital; - break; + s->n_chan = 1; + s->maxdata = board->ao_maxdata; + s->range_table = &range_pcl816; #endif - pcl816_reset(dev); + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl816_do_insn_bits; - printk("\n"); + pcl816_reset(dev); return 0; } -/* -============================================================================== - Removes device - */ -static int pcl816_detach(struct comedi_device *dev) +static void pcl816_detach(struct comedi_device *dev) { - DEBUG(printk(KERN_INFO "comedi%d: pcl816: remove\n", dev->minor);) - free_resources(dev); -#ifdef unused - if (devpriv->dma_rtc) - RTC_lock--; -#endif - return 0; + struct pcl816_private *devpriv = dev->private; + + if (dev->private) { + pcl816_ai_cancel(dev, dev->read_subdev); + pcl816_reset(dev); + if (devpriv->dma) + free_dma(devpriv->dma); + if (devpriv->dmabuf[0]) + free_pages(devpriv->dmabuf[0], devpriv->dmapages); + if (devpriv->dmabuf[1]) + free_pages(devpriv->dmabuf[1], devpriv->dmapages); + } + comedi_legacy_detach(dev); } +static struct comedi_driver pcl816_driver = { + .driver_name = "pcl816", + .module = THIS_MODULE, + .attach = pcl816_attach, + .detach = pcl816_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl816_board), +}; +module_comedi_driver(pcl816_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index 8933e5089bd..7d00ae639d3 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -98,17 +98,17 @@ A word or two about DMA. Driver support DMA operations at two ways: */ -#include "../comedidev.h" - -#include <linux/ioport.h> -#include <linux/mc146818rtc.h> +#include <linux/module.h> #include <linux/gfp.h> #include <linux/delay.h> +#include <linux/io.h> +#include <linux/interrupt.h> #include <asm/dma.h> -#include "8253.h" +#include "../comedidev.h" -/* #define PCL818_MODE13_AO 1 */ +#include "comedi_fc.h" +#include "8253.h" /* boards constants */ @@ -119,46 +119,38 @@ A word or two about DMA. Driver support DMA operations at two ways: #define boardPCL818 4 #define boardPCL718 5 -/* IO space len */ -#define PCLx1x_RANGE 16 -/* IO space len if we use FIFO */ -#define PCLx1xFIFO_RANGE 32 - -/* W: clear INT request */ -#define PCL818_CLRINT 8 -/* R: return status byte */ -#define PCL818_STATUS 8 -/* R: A/D high byte W: A/D range control */ -#define PCL818_RANGE 1 -/* R: next mux scan channel W: mux scan channel & range control pointer */ -#define PCL818_MUX 2 -/* R/W: operation control register */ -#define PCL818_CONTROL 9 -/* W: counter enable */ -#define PCL818_CNTENABLE 10 - -/* R: low byte of A/D W: soft A/D trigger */ -#define PCL818_AD_LO 0 -/* R: high byte of A/D W: A/D range control */ -#define PCL818_AD_HI 1 -/* W: D/A low&high byte */ -#define PCL818_DA_LO 4 -#define PCL818_DA_HI 5 -/* R: low&high byte of DI */ -#define PCL818_DI_LO 3 -#define PCL818_DI_HI 11 -/* W: low&high byte of DO */ -#define PCL818_DO_LO 3 -#define PCL818_DO_HI 11 -/* W: PCL718 second D/A */ -#define PCL718_DA2_LO 6 -#define PCL718_DA2_HI 7 -/* counters */ -#define PCL818_CTR0 12 -#define PCL818_CTR1 13 -#define PCL818_CTR2 14 -/* W: counter control */ -#define PCL818_CTRCTL 15 +/* + * Register I/O map + */ +#define PCL818_AI_LSB_REG 0x00 +#define PCL818_AI_MSB_REG 0x01 +#define PCL818_RANGE_REG 0x01 +#define PCL818_MUX_REG 0x02 +#define PCL818_MUX_SCAN(_first, _last) (((_last) << 4) | (_first)) +#define PCL818_DO_DI_LSB_REG 0x03 +#define PCL818_AO_LSB_REG(x) (0x04 + ((x) * 2)) +#define PCL818_AO_MSB_REG(x) (0x05 + ((x) * 2)) +#define PCL818_STATUS_REG 0x08 +#define PCL818_STATUS_NEXT_CHAN_MASK (0xf << 0) +#define PCL818_STATUS_INT (1 << 4) +#define PCL818_STATUS_MUX (1 << 5) +#define PCL818_STATUS_UNI (1 << 6) +#define PCL818_STATUS_EOC (1 << 7) +#define PCL818_CTRL_REG 0x09 +#define PCL818_CTRL_DISABLE_TRIG (0 << 0) +#define PCL818_CTRL_SOFT_TRIG (1 << 0) +#define PCL818_CTRL_EXT_TRIG (2 << 0) +#define PCL818_CTRL_PACER_TRIG (3 << 0) +#define PCL818_CTRL_DMAE (1 << 2) +#define PCL818_CTRL_IRQ(x) ((x) << 4) +#define PCL818_CTRL_INTE (1 << 7) +#define PCL818_CNTENABLE_REG 0x0a +#define PCL818_CNTENABLE_PACER_ENA (0 << 0) +#define PCL818_CNTENABLE_PACER_TRIG0 (1 << 0) +#define PCL818_CNTENABLE_CNT0_EXT_CLK (0 << 1) +#define PCL818_CNTENABLE_CNT0_INT_CLK (1 << 1) +#define PCL818_DO_DI_MSB_REG 0x0b +#define PCL818_TIMER_BASE 0x0c /* W: fifo enable/disable */ #define PCL818_FI_ENABLE 6 @@ -170,1053 +162,517 @@ A word or two about DMA. Driver support DMA operations at two ways: #define PCL818_FI_STATUS 25 /* R: one record from FIFO */ #define PCL818_FI_DATALO 23 -#define PCL818_FI_DATAHI 23 - -/* type of interrupt handler */ -#define INT_TYPE_AI1_INT 1 -#define INT_TYPE_AI1_DMA 2 -#define INT_TYPE_AI1_FIFO 3 -#define INT_TYPE_AI3_INT 4 -#define INT_TYPE_AI3_DMA 5 -#define INT_TYPE_AI3_FIFO 6 -#ifdef PCL818_MODE13_AO -#define INT_TYPE_AO1_INT 7 -#define INT_TYPE_AO3_INT 8 -#endif - -#ifdef unused -/* RTC stuff... */ -#define INT_TYPE_AI1_DMA_RTC 9 -#define INT_TYPE_AI3_DMA_RTC 10 - -#define RTC_IRQ 8 -#define RTC_IO_EXTENT 0x10 -#endif +#define PCL818_FI_DATAHI 24 #define MAGIC_DMA_WORD 0x5a5a -static const struct comedi_lrange range_pcl818h_ai = { 9, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25), - BIP_RANGE(10), - } +static const struct comedi_lrange range_pcl818h_ai = { + 9, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + BIP_RANGE(10) + } }; -static const struct comedi_lrange range_pcl818hg_ai = { 10, { - BIP_RANGE(5), - BIP_RANGE(0.5), - BIP_RANGE(0.05), - BIP_RANGE(0.005), - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.01), - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.01), - } +static const struct comedi_lrange range_pcl818hg_ai = { + 10, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.005), + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.01), + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_pcl818l_l_ai = { 4, { - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625), - } +static const struct comedi_lrange range_pcl818l_l_ai = { + 4, { + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -static const struct comedi_lrange range_pcl818l_h_ai = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - } +static const struct comedi_lrange range_pcl818l_h_ai = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) + } }; -static const struct comedi_lrange range718_bipolar1 = { 1, {BIP_RANGE(1),} }; -static const struct comedi_lrange range718_bipolar0_5 = - { 1, {BIP_RANGE(0.5),} }; -static const struct comedi_lrange range718_unipolar2 = { 1, {UNI_RANGE(2),} }; -static const struct comedi_lrange range718_unipolar1 = { 1, {BIP_RANGE(1),} }; - -static int pcl818_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcl818_detach(struct comedi_device *dev); - -#ifdef unused -static int RTC_lock = 0; /* RTC lock */ -static int RTC_timer_lock = 0; /* RTC int lock */ -#endif - -struct pcl818_board { - - const char *name; /* driver name */ - int n_ranges; /* len of range list */ - int n_aichan_se; /* num of A/D chans in single ended mode */ - int n_aichan_diff; /* num of A/D chans in diferencial mode */ - unsigned int ns_min; /* minimal allowed delay between samples (in ns) */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - const struct comedi_lrange *ai_range_type; /* default A/D rangelist */ - const struct comedi_lrange *ao_range_type; /* default D/A rangelist */ - unsigned int io_range; /* len of IO space */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int DMAbits; /* allowed DMA chans */ - int ai_maxdata; /* maxdata for A/D */ - int ao_maxdata; /* maxdata for D/A */ - unsigned char fifo; /* 1=board has FIFO */ - int is_818; +static const struct comedi_lrange range718_bipolar1 = { + 1, { + BIP_RANGE(1) + } }; -static const struct pcl818_board boardtypes[] = { - {"pcl818l", 4, 16, 8, 25000, 1, 16, 16, &range_pcl818l_l_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818h", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl818hd", 9, 16, 8, 10000, 1, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818hg", 12, 16, 8, 10000, 1, 16, 16, &range_pcl818hg_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 1, 1}, - {"pcl818", 9, 16, 8, 10000, 2, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1}, - {"pcl718", 1, 16, 8, 16000, 2, 16, 16, &range_unipolar5, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 0}, - /* pcm3718 */ - {"pcm3718", 9, 16, 8, 10000, 0, 16, 16, &range_pcl818h_ai, - &range_unipolar5, PCLx1x_RANGE, 0x00fc, - 0x0a, 0xfff, 0xfff, 0, 1 /* XXX ? */ }, +static const struct comedi_lrange range718_bipolar0_5 = { + 1, { + BIP_RANGE(0.5) + } }; -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcl818_board)) - -static struct comedi_driver driver_pcl818 = { - .driver_name = "pcl818", - .module = THIS_MODULE, - .attach = pcl818_attach, - .detach = pcl818_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcl818_board), +static const struct comedi_lrange range718_unipolar2 = { + 1, { + UNI_RANGE(2) + } }; -static int __init driver_pcl818_init_module(void) -{ - return comedi_driver_register(&driver_pcl818); -} +static const struct comedi_lrange range718_unipolar1 = { + 1, { + BIP_RANGE(1) + } +}; -static void __exit driver_pcl818_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcl818); -} +struct pcl818_board { + const char *name; + unsigned int ns_min; + int n_aochan; + const struct comedi_lrange *ai_range_type; + unsigned int has_dma:1; + unsigned int has_fifo:1; + unsigned int is_818:1; +}; -module_init(driver_pcl818_init_module); -module_exit(driver_pcl818_cleanup_module); +static const struct pcl818_board boardtypes[] = { + { + .name = "pcl818l", + .ns_min = 25000, + .n_aochan = 1, + .ai_range_type = &range_pcl818l_l_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818h", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl818hd", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818hg", + .ns_min = 10000, + .n_aochan = 1, + .ai_range_type = &range_pcl818hg_ai, + .has_dma = 1, + .has_fifo = 1, + .is_818 = 1, + }, { + .name = "pcl818", + .ns_min = 10000, + .n_aochan = 2, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, { + .name = "pcl718", + .ns_min = 16000, + .n_aochan = 2, + .ai_range_type = &range_unipolar5, + .has_dma = 1, + }, { + .name = "pcm3718", + .ns_min = 10000, + .ai_range_type = &range_pcl818h_ai, + .has_dma = 1, + .is_818 = 1, + }, +}; struct pcl818_private { - unsigned int dma; /* used DMA, 0=don't use DMA */ - int dma_rtc; /* 1=RTC used with DMA, 0=no RTC alloc */ - unsigned int io_range; -#ifdef unused - unsigned long rtc_iobase; /* RTC port region */ - unsigned int rtc_iosize; - unsigned int rtc_irq; - struct timer_list rtc_irq_timer; /* timer for RTC sanity check */ - unsigned long rtc_freq; /* RTC int freq */ - int rtc_irq_blocked; /* 1=we now do AI with DMA&RTC */ -#endif + unsigned int dmapages; + unsigned int hwdmasize; unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */ - unsigned int dmapages[2]; /* len of DMA buffers in PAGE_SIZEs */ unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */ - unsigned int hwdmasize[2]; /* len of DMA buffers in Bytes */ - unsigned int dmasamplsize; /* size in samples hwdmasize[0]/2 */ - unsigned int last_top_dma; /* DMA pointer in last RTC int */ int next_dma_buf; /* which DMA buffer will be used next round */ long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */ unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */ - unsigned char neverending_ai; /* if=1, then we do neverending record (you must use cancel()) */ unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */ int i8253_osc_base; /* 1/frequency of on board oscilator in ns */ - int irq_free; /* 1=have allocated IRQ */ - int irq_blocked; /* 1=IRQ now uses any subdev */ - int irq_was_now_closed; /* when IRQ finish, there's stored int818_mode for last interrupt */ - int ai_mode; /* who now uses IRQ - 1=AI1 int, 2=AI1 dma, 3=AI3 int, 4AI3 dma */ - struct comedi_subdevice *last_int_sub; /* ptr to subdevice which now finish */ int ai_act_scan; /* how many scans we finished */ int ai_act_chan; /* actual position in actual scan */ unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */ unsigned int act_chanlist_len; /* how long is actual MUX list */ unsigned int act_chanlist_pos; /* actual position in MUX list */ - unsigned int ai_scans; /* len of scanlist */ - unsigned int ai_n_chan; /* how many channels is measured */ - unsigned int *ai_chanlist; /* actaul chanlist */ - unsigned int ai_flags; /* flaglist */ unsigned int ai_data_len; /* len of data buffer */ - short *ai_data; /* data buffer */ - unsigned int ai_timer1; /* timers */ - unsigned int ai_timer2; - struct comedi_subdevice *sub_ai; /* ptr to AI subdevice */ - unsigned char usefifo; /* 1=use fifo */ unsigned int ao_readback[2]; + unsigned int divisor1; + unsigned int divisor2; + unsigned int usefifo:1; + unsigned int ai_cmd_running:1; + unsigned int ai_cmd_canceled:1; }; -static const unsigned int muxonechan[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, /* used for gain list programming */ - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff -}; - -#define devpriv ((struct pcl818_private *)dev->private) -#define this_board ((const struct pcl818_board *)dev->board_ptr) - -/* -============================================================================== -*/ -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen); -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); - -static int pcl818_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); - -#ifdef unused -static int set_rtc_irq_bit(unsigned char bit); -static void rtc_dropped_irq(unsigned long data); -static int rtc_setfreq_irq(int freq); -#endif - -/* -============================================================================== - ANALOG INPUT MODE0, 818 cards, slow version -*/ -static int pcl818_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters) { - int n; - int timeout; - - /* software trigger, DMA and INT off */ - outb(0, dev->iobase + PCL818_CONTROL); - - /* select channel */ - outb(muxonechan[CR_CHAN(insn->chanspec)], dev->iobase + PCL818_MUX); - - /* select gain */ - outb(CR_RANGE(insn->chanspec), dev->iobase + PCL818_RANGE); - - for (n = 0; n < insn->n; n++) { - - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL818_CLRINT); - - /* start conversion */ - outb(0, dev->iobase + PCL818_AD_LO); + struct pcl818_private *devpriv = dev->private; + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; - timeout = 100; - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - comedi_error(dev, "A/D insn timeout"); - /* clear INT (conversion end) flag */ - outb(0, dev->iobase + PCL818_CLRINT); - return -EIO; - -conv_finish: - data[n] = ((inb(dev->iobase + PCL818_AD_HI) << 4) | - (inb(dev->iobase + PCL818_AD_LO) >> 4)); - } - - return n; -} - -/* -============================================================================== - ANALOG OUTPUT MODE0, 818 cards - only one sample per call is supported -*/ -static int pcl818_ao_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int n; - int chan = CR_CHAN(insn->chanspec); + i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY); + udelay(1); - for (n = 0; n < insn->n; n++) { - data[n] = devpriv->ao_readback[chan]; + if (load_counters) { + i8254_write(timer_base, 0, 2, devpriv->divisor2); + i8254_write(timer_base, 0, 1, devpriv->divisor1); } - - return n; } -static int pcl818_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void pcl818_ai_setup_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - int n; - int chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { - devpriv->ao_readback[chan] = data[n]; - outb((data[n] & 0x000f) << 4, dev->iobase + - (chan ? PCL718_DA2_LO : PCL818_DA_LO)); - outb((data[n] & 0x0ff0) >> 4, dev->iobase + - (chan ? PCL718_DA2_HI : PCL818_DA_HI)); - } - - return n; -} - -/* -============================================================================== - DIGITAL INPUT MODE0, 818 cards - - only one sample per call is supported -*/ -static int pcl818_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = inb(dev->iobase + PCL818_DI_LO) | - (inb(dev->iobase + PCL818_DI_HI) << 8); - - return 2; -} - -/* -============================================================================== - DIGITAL OUTPUT MODE0, 818 cards - - only one sample per call is supported -*/ -static int pcl818_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - outb(s->state & 0xff, dev->iobase + PCL818_DO_LO); - outb((s->state >> 8), dev->iobase + PCL818_DO_HI); - - data[1] = s->state; - - return 2; -} - -/* -============================================================================== - analog input interrupt mode 1 & 3, 818 cards - one sample per interrupt version -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) -{ - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - int low; - int timeout = 50; /* wait max 50us */ - - while (timeout--) { - if (inb(dev->iobase + PCL818_STATUS) & 0x10) - goto conv_finish; - udelay(1); - } - outb(0, dev->iobase + PCL818_STATUS); /* clear INT request */ - comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int flags; + unsigned int bytes; -conv_finish: - low = inb(dev->iobase + PCL818_AD_LO); - comedi_buf_put(s->async, ((inb(dev->iobase + PCL818_AD_HI) << 4) | (low >> 4))); /* get one sample */ - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - - if ((low & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - printk - ("comedi: A/D mode1/3 IRQ - channel dropout %x!=%x !\n", - (low & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { - devpriv->act_chanlist_pos = 0; - } - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - /* printk("E"); */ - s->async->cur_chan = 0; - devpriv->ai_act_scan--; + disable_dma(devpriv->dma); /* disable dma */ + bytes = devpriv->hwdmasize; + if (cmd->stop_src == TRIG_COUNT) { + bytes = cmd->stop_arg * cfc_bytes_per_scan(s); + devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize; + devpriv->last_dma_run = bytes % devpriv->hwdmasize; + devpriv->dma_runs_to_end--; + if (devpriv->dma_runs_to_end >= 0) + bytes = devpriv->hwdmasize; } - if (!devpriv->neverending_ai) { - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - } - } - comedi_event(dev, s); - return IRQ_HANDLED; + devpriv->next_dma_buf = 0; + set_dma_mode(devpriv->dma, DMA_MODE_READ); + flags = claim_dma_lock(); + clear_dma_ff(devpriv->dma); + set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); + set_dma_count(devpriv->dma, bytes); + release_dma_lock(flags); + enable_dma(devpriv->dma); } -/* -============================================================================== - analog input dma mode 1 & 3, 818 cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) +static void pcl818_ai_setup_next_dma(struct comedi_device *dev, + struct comedi_subdevice *s) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - int i, len, bufptr; + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; - short *ptr; disable_dma(devpriv->dma); devpriv->next_dma_buf = 1 - devpriv->next_dma_buf; - if ((devpriv->dma_runs_to_end) > -1 || devpriv->neverending_ai) { /* switch dma bufs */ + if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) { + /* switch dma bufs */ set_dma_mode(devpriv->dma, DMA_MODE_READ); flags = claim_dma_lock(); set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]); - if (devpriv->dma_runs_to_end || devpriv->neverending_ai) { - set_dma_count(devpriv->dma, - devpriv->hwdmasize[devpriv-> - next_dma_buf]); - } else { + if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE) + set_dma_count(devpriv->dma, devpriv->hwdmasize); + else set_dma_count(devpriv->dma, devpriv->last_dma_run); - } release_dma_lock(flags); enable_dma(devpriv->dma); } - printk("comedi: A/D mode1/3 IRQ \n"); devpriv->dma_runs_to_end--; - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - ptr = (short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; - - len = devpriv->hwdmasize[0] >> 1; - bufptr = 0; - - for (i = 0; i < len; i++) { - if ((ptr[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - printk - ("comedi: A/D mode1/3 DMA - channel dropout %d(card)!=%d(chanlist) at %d !\n", - (ptr[bufptr] & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos], - devpriv->act_chanlist_pos); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - - comedi_buf_put(s->async, ptr[bufptr++] >> 4); /* get one sample */ - - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { - devpriv->act_chanlist_pos = 0; - } - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } - - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - /* printk("done int ai13 dma\n"); */ - return IRQ_HANDLED; - } - } +} - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; +static void pcl818_ai_set_chan_range(struct comedi_device *dev, + unsigned int chan, + unsigned int range) +{ + outb(chan, dev->iobase + PCL818_MUX_REG); + outb(range, dev->iobase + PCL818_RANGE_REG); } -#ifdef unused -/* -============================================================================== - analog input dma mode 1 & 3 over RTC, 818 cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) +static void pcl818_ai_set_chan_scan(struct comedi_device *dev, + unsigned int first_chan, + unsigned int last_chan) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - unsigned long tmp; - unsigned int top1, top2, i, bufptr; - long ofs_dats; - short *dmabuf = (short *)devpriv->dmabuf[0]; - - /* outb(2,0x378); */ - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA_RTC: - case INT_TYPE_AI3_DMA_RTC: - tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); - mod_timer(&devpriv->rtc_irq_timer, - jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100); - - for (i = 0; i < 10; i++) { - top1 = get_dma_residue(devpriv->dma); - top2 = get_dma_residue(devpriv->dma); - if (top1 == top2) - break; - } + outb(PCL818_MUX_SCAN(first_chan, last_chan), + dev->iobase + PCL818_MUX_REG); +} - if (top1 != top2) - return IRQ_HANDLED; - top1 = devpriv->hwdmasize[0] - top1; /* where is now DMA in buffer */ - top1 >>= 1; - ofs_dats = top1 - devpriv->last_top_dma; /* new samples from last call */ - if (ofs_dats < 0) - ofs_dats = (devpriv->dmasamplsize) + ofs_dats; - if (!ofs_dats) - return IRQ_HANDLED; /* exit=no new samples from last call */ - /* obsluz data */ - i = devpriv->last_top_dma - 1; - i &= (devpriv->dmasamplsize - 1); - - if (dmabuf[i] != MAGIC_DMA_WORD) { /* DMA overflow! */ - comedi_error(dev, "A/D mode1/3 DMA buffer overflow!"); - /* printk("I %d dmabuf[i] %d %d\n",i,dmabuf[i],devpriv->dmasamplsize); */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } - /* printk("r %ld ",ofs_dats); */ - - bufptr = devpriv->last_top_dma; - - for (i = 0; i < ofs_dats; i++) { - if ((dmabuf[bufptr] & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - printk - ("comedi: A/D mode1/3 DMA - channel dropout %d!=%d !\n", - (dmabuf[bufptr] & 0xf), - devpriv-> - act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); - s->async->events |= - COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } +static void pcl818_ai_setup_chanlist(struct comedi_device *dev, + unsigned int *chanlist, + unsigned int seglen) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int first_chan = CR_CHAN(chanlist[0]); + unsigned int last_chan; + unsigned int range; + int i; - comedi_buf_put(s->async, dmabuf[bufptr++] >> 4); /* get one sample */ - bufptr &= (devpriv->dmasamplsize - 1); + devpriv->act_chanlist_len = seglen; + devpriv->act_chanlist_pos = 0; - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= - devpriv->act_chanlist_len) { - devpriv->act_chanlist_pos = 0; - } - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } + /* store range list to card */ + for (i = 0; i < seglen; i++) { + last_chan = CR_CHAN(chanlist[i]); + range = CR_RANGE(chanlist[i]); - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - /* printk("done int ai13 dma\n"); */ - return IRQ_HANDLED; - } - } + devpriv->act_chanlist[i] = last_chan; - devpriv->last_top_dma = bufptr; - bufptr--; - bufptr &= (devpriv->dmasamplsize - 1); - dmabuf[bufptr] = MAGIC_DMA_WORD; - comedi_event(dev, s); - /* outb(0,0x378); */ - return IRQ_HANDLED; + pcl818_ai_set_chan_range(dev, last_chan, range); } - /* outb(0,0x378); */ - return IRQ_HANDLED; + udelay(1); + + pcl818_ai_set_chan_scan(dev, first_chan, last_chan); } -#endif -/* -============================================================================== - analog input interrupt mode 1 & 3, 818HD/HG cards -*/ -static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) +static void pcl818_ai_clear_eoc(struct comedi_device *dev) { - struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; - int i, len, lo; - - outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ + /* writing any value clears the interrupt request */ + outb(0, dev->iobase + PCL818_STATUS_REG); +} - lo = inb(dev->iobase + PCL818_FI_STATUS); +static void pcl818_ai_soft_trig(struct comedi_device *dev) +{ + /* writing any value triggers a software conversion */ + outb(0, dev->iobase + PCL818_AI_LSB_REG); +} - if (lo & 4) { - comedi_error(dev, "A/D mode1/3 FIFO overflow!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } +static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) +{ + unsigned int val; - if (lo & 1) { - comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!"); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } + val = inb(dev->iobase + PCL818_FI_DATALO); + val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8); - if (lo & 2) { - len = 512; - } else { - len = 0; - } + if (chan) + *chan = val & 0xf; - for (i = 0; i < len; i++) { - lo = inb(dev->iobase + PCL818_FI_DATALO); - if ((lo & 0xf) != devpriv->act_chanlist[devpriv->act_chanlist_pos]) { /* dropout! */ - printk - ("comedi: A/D mode1/3 FIFO - channel dropout %d!=%d !\n", - (lo & 0xf), - devpriv->act_chanlist[devpriv->act_chanlist_pos]); - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; - comedi_event(dev, s); - return IRQ_HANDLED; - } + return (val >> 4) & s->maxdata; +} - comedi_buf_put(s->async, (lo >> 4) | (inb(dev->iobase + PCL818_FI_DATAHI) << 4)); /* get one sample */ +static unsigned int pcl818_ai_get_sample(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *chan) +{ + unsigned int val; - devpriv->act_chanlist_pos++; - if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) { - devpriv->act_chanlist_pos = 0; - } - s->async->cur_chan++; - if (s->async->cur_chan >= devpriv->ai_n_chan) { - s->async->cur_chan = 0; - devpriv->ai_act_scan--; - } + val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8; + val |= inb(dev->iobase + PCL818_AI_LSB_REG); - if (!devpriv->neverending_ai) - if (devpriv->ai_act_scan == 0) { /* all data sampled */ - pcl818_ai_cancel(dev, s); - s->async->events |= COMEDI_CB_EOA; - comedi_event(dev, s); - return IRQ_HANDLED; - } - } + if (chan) + *chan = val & 0xf; - if (len > 0) - comedi_event(dev, s); - return IRQ_HANDLED; + return (val >> 4) & s->maxdata; } -/* -============================================================================== - INT procedure -*/ -static irqreturn_t interrupt_pcl818(int irq, void *d) +static int pcl818_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - struct comedi_device *dev = d; + unsigned int status; - if (!dev->attached) { - comedi_error(dev, "premature interrupt"); - return IRQ_HANDLED; + status = inb(dev->iobase + PCL818_STATUS_REG); + if (status & PCL818_STATUS_INT) + return 0; + return -EBUSY; +} + +static bool pcl818_ai_dropout(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan) +{ + struct pcl818_private *devpriv = dev->private; + unsigned int expected_chan; + + expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos]; + if (chan != expected_chan) { + dev_dbg(dev->class_dev, + "A/D mode1/3 %s - channel dropout %d!=%d !\n", + (devpriv->dma) ? "DMA" : + (devpriv->usefifo) ? "FIFO" : "IRQ", + chan, expected_chan); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return true; } - /* printk("I\n"); */ - - if (devpriv->irq_blocked && devpriv->irq_was_now_closed) { - if ((devpriv->neverending_ai || (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) && - (devpriv->ai_mode == INT_TYPE_AI1_DMA || - devpriv->ai_mode == INT_TYPE_AI3_DMA)) { - /* The cleanup from ai_cancel() has been delayed - until now because the card doesn't seem to like - being reprogrammed while a DMA transfer is in - progress. - */ - struct comedi_subdevice *s = dev->subdevices + 0; - devpriv->ai_act_scan = 0; - devpriv->neverending_ai = 0; - pcl818_ai_cancel(dev, s); - } + return false; +} - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ +static bool pcl818_ai_next_chan(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; - return IRQ_HANDLED; - } + s->async->events |= COMEDI_CB_BLOCK; - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - return interrupt_pcl818_ai_mode13_dma(irq, d); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - return interrupt_pcl818_ai_mode13_int(irq, d); - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: - return interrupt_pcl818_ai_mode13_fifo(irq, d); -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: - return interrupt_pcl818_ao_mode13_int(irq, d); -#endif - default: - break; - } + devpriv->act_chanlist_pos++; + if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len) + devpriv->act_chanlist_pos = 0; - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ + s->async->cur_chan++; + if (s->async->cur_chan >= cmd->chanlist_len) { + s->async->cur_chan = 0; + devpriv->ai_act_scan--; + s->async->events |= COMEDI_CB_EOS; + } - if ((!dev->irq) || (!devpriv->irq_free) || (!devpriv->irq_blocked) - || (!devpriv->ai_mode)) { - comedi_error(dev, "bad IRQ!"); - return IRQ_NONE; + if (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan == 0) { + /* all data sampled */ + s->async->events |= COMEDI_CB_EOA; + return false; } - comedi_error(dev, "IRQ from unknown source!"); - return IRQ_NONE; + return true; } -/* -============================================================================== - ANALOG INPUT MODE 1 or 3 DMA , 818 cards -*/ -static void pcl818_ai_mode13dma_int(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) +static void pcl818_handle_eoc(struct comedi_device *dev, + struct comedi_subdevice *s) { - unsigned int flags; - unsigned int bytes; + unsigned int chan; + unsigned int val; - printk("mode13dma_int, mode: %d\n", mode); - disable_dma(devpriv->dma); /* disable dma */ - bytes = devpriv->hwdmasize[0]; - if (!devpriv->neverending_ai) { - bytes = devpriv->ai_n_chan * devpriv->ai_scans * sizeof(short); /* how many */ - devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize[0]; /* how many DMA pages we must fiil */ - devpriv->last_dma_run = bytes % devpriv->hwdmasize[0]; /* on last dma transfer must be moved */ - devpriv->dma_runs_to_end--; - if (devpriv->dma_runs_to_end >= 0) - bytes = devpriv->hwdmasize[0]; + if (pcl818_ai_eoc(dev, s, NULL, 0)) { + comedi_error(dev, "A/D mode1/3 IRQ without DRDY!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; } - devpriv->next_dma_buf = 0; - set_dma_mode(devpriv->dma, DMA_MODE_READ); - flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, bytes); - release_dma_lock(flags); - enable_dma(devpriv->dma); + val = pcl818_ai_get_sample(dev, s, &chan); - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_DMA; - outb(0x87 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ+DMA */ - } else { - devpriv->ai_mode = INT_TYPE_AI3_DMA; - outb(0x86 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ+DMA */ - }; -} + if (pcl818_ai_dropout(dev, s, chan)) + return; -#ifdef unused -/* -============================================================================== - ANALOG INPUT MODE 1 or 3 DMA rtc, 818 cards -*/ -static void pcl818_ai_mode13dma_rtc(int mode, struct comedi_device *dev, - struct comedi_subdevice *s) -{ - unsigned int flags; - short *pole; + comedi_buf_put(s, val); - set_dma_mode(devpriv->dma, DMA_MODE_READ | DMA_AUTOINIT); - flags = claim_dma_lock(); - clear_dma_ff(devpriv->dma); - set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]); - set_dma_count(devpriv->dma, devpriv->hwdmasize[0]); - release_dma_lock(flags); - enable_dma(devpriv->dma); - devpriv->last_top_dma = 0; /* devpriv->hwdmasize[0]; */ - pole = (short *)devpriv->dmabuf[0]; - devpriv->dmasamplsize = devpriv->hwdmasize[0] / 2; - pole[devpriv->dmasamplsize - 1] = MAGIC_DMA_WORD; -#ifdef unused - devpriv->rtc_freq = rtc_setfreq_irq(2048); - devpriv->rtc_irq_timer.expires = - jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100; - devpriv->rtc_irq_timer.data = (unsigned long)dev; - devpriv->rtc_irq_timer.function = rtc_dropped_irq; - - add_timer(&devpriv->rtc_irq_timer); -#endif - - if (mode == 1) { - devpriv->int818_mode = INT_TYPE_AI1_DMA_RTC; - outb(0x07 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+DMA */ - } else { - devpriv->int818_mode = INT_TYPE_AI3_DMA_RTC; - outb(0x06 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+DMA */ - }; + pcl818_ai_next_chan(dev, s); } -#endif -/* -============================================================================== - ANALOG INPUT MODE 1 or 3, 818 cards -*/ -static int pcl818_ai_cmd_mode(int mode, struct comedi_device *dev, +static void pcl818_handle_dma(struct comedi_device *dev, struct comedi_subdevice *s) { - struct comedi_cmd *cmd = &s->async->cmd; - int divisor1 = 0, divisor2 = 0; - unsigned int seglen; - - printk("pcl818_ai_cmd_mode()\n"); - if ((!dev->irq) && (!devpriv->dma_rtc)) { - comedi_error(dev, "IRQ not defined!"); - return -EINVAL; - } - - if (devpriv->irq_blocked) - return -EBUSY; + struct pcl818_private *devpriv = dev->private; + unsigned short *ptr; + unsigned int chan; + unsigned int val; + int i, len, bufptr; - start_pacer(dev, -1, 0, 0); /* stop pacer */ + pcl818_ai_setup_next_dma(dev, s); - seglen = check_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan); - if (seglen < 1) - return -EINVAL; - setup_channel_list(dev, s, devpriv->ai_chanlist, - devpriv->ai_n_chan, seglen); + ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf]; - udelay(1); - - devpriv->ai_act_scan = devpriv->ai_scans; - devpriv->ai_act_chan = 0; - devpriv->irq_blocked = 1; - devpriv->irq_was_now_closed = 0; - devpriv->neverending_ai = 0; - devpriv->act_chanlist_pos = 0; - devpriv->dma_runs_to_end = 0; - - if ((devpriv->ai_scans == 0) || (devpriv->ai_scans == -1)) - devpriv->neverending_ai = 1; /* well, user want neverending */ - - if (mode == 1) { - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - TRIG_ROUND_NEAREST); - if (divisor1 == 1) { /* PCL718/818 crash if any divisor is set to 1 */ - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } - } + len = devpriv->hwdmasize >> 1; + bufptr = 0; - outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ + for (i = 0; i < len; i++) { + val = ptr[bufptr++]; + chan = val & 0xf; + val = (val >> 4) & s->maxdata; - switch (devpriv->dma) { - case 1: /* DMA */ - case 3: - if (devpriv->dma_rtc == 0) { - pcl818_ai_mode13dma_int(mode, dev, s); - } -#ifdef unused - else { - pcl818_ai_mode13dma_rtc(mode, dev, s); - } -#else - else { - return -EINVAL; - } -#endif - break; - case 0: - if (!devpriv->usefifo) { - /* IRQ */ - /* printk("IRQ\n"); */ - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_INT; - /* Pacer+IRQ */ - outb(0x83 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_INT; - /* Ext trig+IRQ */ - outb(0x82 | (dev->irq << 4), - dev->iobase + PCL818_CONTROL); - } - } else { - /* FIFO */ - /* enable FIFO */ - outb(1, dev->iobase + PCL818_FI_ENABLE); - if (mode == 1) { - devpriv->ai_mode = INT_TYPE_AI1_FIFO; - /* Pacer */ - outb(0x03, dev->iobase + PCL818_CONTROL); - } else { - devpriv->ai_mode = INT_TYPE_AI3_FIFO; - outb(0x02, dev->iobase + PCL818_CONTROL); - } - } - } + if (pcl818_ai_dropout(dev, s, chan)) + break; - start_pacer(dev, mode, divisor1, divisor2); + comedi_buf_put(s, val); -#ifdef unused - switch (devpriv->ai_mode) { - case INT_TYPE_AI1_DMA_RTC: - case INT_TYPE_AI3_DMA_RTC: - set_rtc_irq_bit(1); /* start RTC */ - break; + if (!pcl818_ai_next_chan(dev, s)) + break; } -#endif - printk("pcl818_ai_cmd_mode() end\n"); - return 0; } -#ifdef unused -/* -============================================================================== - ANALOG OUTPUT MODE 1 or 3, 818 cards -*/ -#ifdef PCL818_MODE13_AO -static int pcl818_ao_mode13(int mode, struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig * it) +static void pcl818_handle_fifo(struct comedi_device *dev, + struct comedi_subdevice *s) { - int divisor1 = 0, divisor2 = 0; + unsigned int status; + unsigned int chan; + unsigned int val; + int i, len; - if (!dev->irq) { - comedi_error(dev, "IRQ not defined!"); - return -EINVAL; - } + status = inb(dev->iobase + PCL818_FI_STATUS); - if (devpriv->irq_blocked) - return -EBUSY; - - start_pacer(dev, -1, 0, 0); /* stop pacer */ - - devpriv->int13_act_scan = it->n; - devpriv->int13_act_chan = 0; - devpriv->irq_blocked = 1; - devpriv->irq_was_now_closed = 0; - devpriv->neverending_ai = 0; - devpriv->act_chanlist_pos = 0; + if (status & 4) { + comedi_error(dev, "A/D mode1/3 FIFO overflow!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; + } - if (mode == 1) { - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, - &divisor2, &it->trigvar, - TRIG_ROUND_NEAREST); - if (divisor1 == 1) { /* PCL818 crash if any divisor is set to 1 */ - divisor1 = 2; - divisor2 /= 2; - } - if (divisor2 == 1) { - divisor2 = 2; - divisor1 /= 2; - } + if (status & 1) { + comedi_error(dev, "A/D mode1/3 FIFO interrupt without data!"); + s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; + return; } - outb(0, dev->iobase + PCL818_CNTENABLE); /* enable pacer */ - if (mode == 1) { - devpriv->int818_mode = INT_TYPE_AO1_INT; - outb(0x83 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Pacer+IRQ */ - } else { - devpriv->int818_mode = INT_TYPE_AO3_INT; - outb(0x82 | (dev->irq << 4), dev->iobase + PCL818_CONTROL); /* Ext trig+IRQ */ - }; + if (status & 2) + len = 512; + else + len = 0; - start_pacer(dev, mode, divisor1, divisor2); + for (i = 0; i < len; i++) { + val = pcl818_ai_get_fifo_sample(dev, s, &chan); - return 0; -} + if (pcl818_ai_dropout(dev, s, chan)) + break; -/* -============================================================================== - ANALOG OUTPUT MODE 1, 818 cards -*/ -static int pcl818_ao_mode1(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig * it) -{ - return pcl818_ao_mode13(1, dev, s, it); -} + comedi_buf_put(s, val); -/* -============================================================================== - ANALOG OUTPUT MODE 3, 818 cards -*/ -static int pcl818_ao_mode3(struct comedi_device *dev, - struct comedi_subdevice *s, comedi_trig * it) -{ - return pcl818_ao_mode13(3, dev, s, it); + if (!pcl818_ai_next_chan(dev, s)) + break; + } } -#endif -#endif -/* -============================================================================== - Start/stop pacer onboard pacer -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) +static irqreturn_t pcl818_interrupt(int irq, void *d) { - outb(0xb4, dev->iobase + PCL818_CTRCTL); - outb(0x74, dev->iobase + PCL818_CTRCTL); - udelay(1); + struct comedi_device *dev = d; + struct pcl818_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; - if (mode == 1) { - outb(divisor2 & 0xff, dev->iobase + PCL818_CTR2); - outb((divisor2 >> 8) & 0xff, dev->iobase + PCL818_CTR2); - outb(divisor1 & 0xff, dev->iobase + PCL818_CTR1); - outb((divisor1 >> 8) & 0xff, dev->iobase + PCL818_CTR1); + if (!dev->attached || !devpriv->ai_cmd_running) { + pcl818_ai_clear_eoc(dev); + return IRQ_HANDLED; } + + if (devpriv->ai_cmd_canceled) { + /* + * The cleanup from ai_cancel() has been delayed + * until now because the card doesn't seem to like + * being reprogrammed while a DMA transfer is in + * progress. + */ + devpriv->ai_act_scan = 0; + s->cancel(dev, s); + return IRQ_HANDLED; + } + + if (devpriv->dma) + pcl818_handle_dma(dev, s); + else if (devpriv->usefifo) + pcl818_handle_fifo(dev, s); + else + pcl818_handle_eoc(dev, s); + + pcl818_ai_clear_eoc(dev); + + cfc_handle_events(dev, s); + return IRQ_HANDLED; } -/* -============================================================================== - Check if channel list from user is builded correctly - If it's ok, then program scan/gain logic -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) @@ -1235,10 +691,6 @@ static int check_channel_list(struct comedi_device *dev, chansegment[0] = chanlist[0]; /* build part of chanlist */ for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { - - /* printk("%d. %d * %d\n",i, - * CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i]));*/ - /* we detect loop, this must by finish */ if (chanlist[0] == chanlist[i]) @@ -1246,10 +698,10 @@ static int check_channel_list(struct comedi_device *dev, nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */ - printk - ("comedi%d: pcl818: channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", - dev->minor, i, CR_CHAN(chanlist[i]), - nowmustbechan, CR_CHAN(chanlist[0])); + dev_dbg(dev->class_dev, + "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", + i, CR_CHAN(chanlist[i]), nowmustbechan, + CR_CHAN(chanlist[0])); return 0; } /* well, this is next correct channel in list */ @@ -1258,188 +710,94 @@ static int check_channel_list(struct comedi_device *dev, /* check whole chanlist */ for (i = 0, segpos = 0; i < n_chan; i++) { - /* printk("%d %d=%d %d\n",CR_CHAN(chansegment[i%seglen]),CR_RANGE(chansegment[i%seglen]),CR_CHAN(it->chanlist[i]),CR_RANGE(it->chanlist[i])); */ if (chanlist[i] != chansegment[i % seglen]) { - printk - ("comedi%d: pcl818: bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", - dev->minor, i, CR_CHAN(chansegment[i]), - CR_RANGE(chansegment[i]), - CR_AREF(chansegment[i]), - CR_CHAN(chanlist[i % seglen]), - CR_RANGE(chanlist[i % seglen]), - CR_AREF(chansegment[i % seglen])); + dev_dbg(dev->class_dev, + "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", + i, CR_CHAN(chansegment[i]), + CR_RANGE(chansegment[i]), + CR_AREF(chansegment[i]), + CR_CHAN(chanlist[i % seglen]), + CR_RANGE(chanlist[i % seglen]), + CR_AREF(chansegment[i % seglen])); return 0; /* chan/gain list is strange */ } } } else { seglen = 1; } - printk("check_channel_list: seglen %d\n", seglen); return seglen; } -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen) -{ - int i; - - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - - for (i = 0; i < seglen; i++) { /* store range list to card */ - devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]); - outb(muxonechan[CR_CHAN(chanlist[i])], dev->iobase + PCL818_MUX); /* select channel */ - outb(CR_RANGE(chanlist[i]), dev->iobase + PCL818_RANGE); /* select gain */ - } - - udelay(1); - - /* select channel interval to scan */ - outb(devpriv->act_chanlist[0] | (devpriv->act_chanlist[seglen - - 1] << 4), - dev->iobase + PCL818_MUX); -} - -/* -============================================================================== - Check if board is switched to SE (1) or DIFF(0) mode -*/ static int check_single_ended(unsigned int port) { - if (inb(port + PCL818_STATUS) & 0x20) { + if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX) return 1; - } else { - return 0; - } + return 0; } -/* -============================================================================== -*/ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct pcl818_board *board = comedi_board(dev); + struct pcl818_private *devpriv = dev->private; int err = 0; - int tmp, divisor1 = 0, divisor2 = 0; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + unsigned int arg; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + 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); - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) { + if (err) return 1; - } - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW) { - cmd->start_src = TRIG_NOW; - err++; - } - if (cmd->scan_begin_src != TRIG_FOLLOW) { - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } + /* Step 2b : and mutually compatible */ - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; - - if (err) { + if (err) return 2; - } - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + board->ns_min); + else /* TRIG_EXT */ + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0); - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < this_board->ns_min) { - cmd->convert_arg = this_board->ns_min; - err++; - } - } else { /* TRIG_EXT */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } - } else { /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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) { + if (err) return 3; - } /* step 4: fix up any arguments */ if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, &divisor1, - &divisor2, &cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (cmd->convert_arg < this_board->ns_min) - cmd->convert_arg = this_board->ns_min; - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + i8253_cascade_ns_to_timer(devpriv->i8253_osc_base, + &devpriv->divisor1, + &devpriv->divisor2, + &arg, cmd->flags); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } - if (err) { + if (err) return 4; - } /* step 5: complain about special chanlist considerations */ @@ -1452,531 +810,370 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, return 0; } -/* -============================================================================== -*/ -static int ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +static int pcl818_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) { + struct pcl818_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - int retval; + unsigned int ctrl = 0; + unsigned int seglen; + + if (devpriv->ai_cmd_running) + return -EBUSY; + + pcl818_start_pacer(dev, false); + + seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len); + if (seglen < 1) + return -EINVAL; + pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen); - printk("pcl818_ai_cmd()\n"); - devpriv->ai_n_chan = cmd->chanlist_len; - devpriv->ai_chanlist = cmd->chanlist; - devpriv->ai_flags = cmd->flags; devpriv->ai_data_len = s->async->prealloc_bufsz; - devpriv->ai_data = s->async->prealloc_buf; - devpriv->ai_timer1 = 0; - devpriv->ai_timer2 = 0; + devpriv->ai_act_scan = cmd->stop_arg; + devpriv->ai_act_chan = 0; + devpriv->ai_cmd_running = 1; + devpriv->ai_cmd_canceled = 0; + devpriv->act_chanlist_pos = 0; + devpriv->dma_runs_to_end = 0; - if (cmd->stop_src == TRIG_COUNT) { - devpriv->ai_scans = cmd->stop_arg; + if (cmd->convert_src == TRIG_TIMER) + ctrl |= PCL818_CTRL_PACER_TRIG; + else + ctrl |= PCL818_CTRL_EXT_TRIG; + + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + + if (devpriv->dma) { + pcl818_ai_setup_dma(dev, s); + + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) | + PCL818_CTRL_DMAE; + } else if (devpriv->usefifo) { + /* enable FIFO */ + outb(1, dev->iobase + PCL818_FI_ENABLE); } else { - devpriv->ai_scans = 0; + ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq); } + outb(ctrl, dev->iobase + PCL818_CTRL_REG); - if (cmd->scan_begin_src == TRIG_FOLLOW) { /* mode 1, 3 */ - if (cmd->convert_src == TRIG_TIMER) { /* mode 1 */ - devpriv->ai_timer1 = cmd->convert_arg; - retval = pcl818_ai_cmd_mode(1, dev, s); - printk("pcl818_ai_cmd() end\n"); - return retval; - } - if (cmd->convert_src == TRIG_EXT) { /* mode 3 */ - return pcl818_ai_cmd_mode(3, dev, s); - } - } + if (cmd->convert_src == TRIG_TIMER) + pcl818_start_pacer(dev, true); - return -1; + return 0; } -/* -============================================================================== - cancel any mode 1-4 AI -*/ static int pcl818_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - if (devpriv->irq_blocked > 0) { - printk("pcl818_ai_cancel()\n"); - devpriv->irq_was_now_closed = 1; - - switch (devpriv->ai_mode) { -#ifdef unused - case INT_TYPE_AI1_DMA_RTC: - case INT_TYPE_AI3_DMA_RTC: - set_rtc_irq_bit(0); /* stop RTC */ - del_timer(&devpriv->rtc_irq_timer); -#endif - case INT_TYPE_AI1_DMA: - case INT_TYPE_AI3_DMA: - if (devpriv->neverending_ai || - (!devpriv->neverending_ai && - devpriv->ai_act_scan > 0)) { - /* wait for running dma transfer to end, do cleanup in interrupt */ - goto end; - } - disable_dma(devpriv->dma); - case INT_TYPE_AI1_INT: - case INT_TYPE_AI3_INT: - case INT_TYPE_AI1_FIFO: - case INT_TYPE_AI3_FIFO: -#ifdef PCL818_MODE13_AO - case INT_TYPE_AO1_INT: - case INT_TYPE_AO3_INT: -#endif - outb(inb(dev->iobase + PCL818_CONTROL) & 0x73, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - udelay(1); - start_pacer(dev, -1, 0, 0); - outb(0, dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_LO); - inb(dev->iobase + PCL818_AD_HI); - outb(0, dev->iobase + PCL818_CLRINT); /* clear INT request */ - outb(0, dev->iobase + PCL818_CONTROL); /* Stop A/D */ - if (devpriv->usefifo) { /* FIFO shutdown */ - outb(0, dev->iobase + PCL818_FI_INTCLR); - outb(0, dev->iobase + PCL818_FI_FLUSH); - outb(0, dev->iobase + PCL818_FI_ENABLE); + struct pcl818_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + + if (!devpriv->ai_cmd_running) + return 0; + + if (devpriv->dma) { + if (cmd->stop_src == TRIG_NONE || + (cmd->stop_src == TRIG_COUNT && devpriv->ai_act_scan > 0)) { + if (!devpriv->ai_cmd_canceled) { + /* + * Wait for running dma transfer to end, + * do cleanup in interrupt. + */ + devpriv->ai_cmd_canceled = 1; + return 0; } - devpriv->irq_blocked = 0; - devpriv->last_int_sub = s; - devpriv->neverending_ai = 0; - devpriv->ai_mode = 0; - devpriv->irq_was_now_closed = 0; - break; } + disable_dma(devpriv->dma); } -end: - printk("pcl818_ai_cancel() end\n"); - return 0; -} + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_start_pacer(dev, false); + pcl818_ai_clear_eoc(dev); -/* -============================================================================== - chech for PCL818 -*/ -static int pcl818_check(unsigned long iobase) -{ - outb(0x00, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x00) - return 1; /* there isn't card */ - outb(0x55, iobase + PCL818_MUX); - udelay(1); - if (inb(iobase + PCL818_MUX) != 0x55) - return 1; /* there isn't card */ - outb(0x00, iobase + PCL818_MUX); - udelay(1); - outb(0x18, iobase + PCL818_CONTROL); - udelay(1); - if (inb(iobase + PCL818_CONTROL) != 0x18) - return 1; /* there isn't card */ - return 0; /* ok, card exist */ -} - -/* -============================================================================== - reset whole PCL-818 cards -*/ -static void pcl818_reset(struct comedi_device *dev) -{ if (devpriv->usefifo) { /* FIFO shutdown */ outb(0, dev->iobase + PCL818_FI_INTCLR); outb(0, dev->iobase + PCL818_FI_FLUSH); outb(0, dev->iobase + PCL818_FI_ENABLE); } - outb(0, dev->iobase + PCL818_DA_LO); /* DAC=0V */ - outb(0, dev->iobase + PCL818_DA_HI); - udelay(1); - outb(0, dev->iobase + PCL818_DO_HI); /* DO=$0000 */ - outb(0, dev->iobase + PCL818_DO_LO); - udelay(1); - outb(0, dev->iobase + PCL818_CONTROL); - outb(0, dev->iobase + PCL818_CNTENABLE); - outb(0, dev->iobase + PCL818_MUX); - outb(0, dev->iobase + PCL818_CLRINT); - outb(0xb0, dev->iobase + PCL818_CTRCTL); /* Stop pacer */ - outb(0x70, dev->iobase + PCL818_CTRCTL); - outb(0x30, dev->iobase + PCL818_CTRCTL); - if (this_board->is_818) { - outb(0, dev->iobase + PCL818_RANGE); - } else { - outb(0, dev->iobase + PCL718_DA2_LO); - outb(0, dev->iobase + PCL718_DA2_HI); - } + devpriv->ai_cmd_running = 0; + devpriv->ai_cmd_canceled = 0; + + return 0; } -#ifdef unused -/* -============================================================================== - Enable(1)/disable(0) periodic interrupts from RTC -*/ -static int set_rtc_irq_bit(unsigned char bit) +static int pcl818_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned char val; - unsigned long flags; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + int ret = 0; + int i; - if (bit == 1) { - RTC_timer_lock++; - if (RTC_timer_lock > 1) - return 0; - } else { - RTC_timer_lock--; - if (RTC_timer_lock < 0) - RTC_timer_lock = 0; - if (RTC_timer_lock > 0) - return 0; - } + outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG); - save_flags(flags); - cli(); - val = CMOS_READ(RTC_CONTROL); - if (bit) { - val |= RTC_PIE; - } else { - val &= ~RTC_PIE; + pcl818_ai_set_chan_range(dev, chan, range); + pcl818_ai_set_chan_scan(dev, chan, chan); + + for (i = 0; i < insn->n; i++) { + pcl818_ai_clear_eoc(dev); + pcl818_ai_soft_trig(dev); + + ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0); + if (ret) + break; + + data[i] = pcl818_ai_get_sample(dev, s, NULL); } - CMOS_WRITE(val, RTC_CONTROL); - CMOS_READ(RTC_INTR_FLAGS); - restore_flags(flags); - return 0; + pcl818_ai_clear_eoc(dev); + + return ret ? ret : insn->n; } -/* -============================================================================== - Restart RTC if something stop it (xntpd every 11 mins or large IDE transfers) -*/ -static void rtc_dropped_irq(unsigned long data) +static int pcl818_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct comedi_device *dev = (void *)data; - unsigned long flags, tmp; - - switch (devpriv->int818_mode) { - case INT_TYPE_AI1_DMA_RTC: - case INT_TYPE_AI3_DMA_RTC: - mod_timer(&devpriv->rtc_irq_timer, - jiffies + HZ / devpriv->rtc_freq + 2 * HZ / 100); - save_flags(flags); - cli(); - tmp = (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */ - restore_flags(flags); - break; + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) { + devpriv->ao_readback[chan] = data[i]; + outb((data[i] & 0x000f) << 4, + dev->iobase + PCL818_AO_LSB_REG(chan)); + outb((data[i] & 0x0ff0) >> 4, + dev->iobase + PCL818_AO_MSB_REG(chan)); } + + return insn->n; } -/* -============================================================================== - Set frequency of interrupts from RTC -*/ -static int rtc_setfreq_irq(int freq) +static int pcl818_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int tmp = 0; - int rtc_freq; - unsigned char val; - unsigned long flags; + struct pcl818_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; - if (freq < 2) - freq = 2; - if (freq > 8192) - freq = 8192; + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - while (freq > (1 << tmp)) - tmp++; + return insn->n; +} - rtc_freq = 1 << tmp; +static int pcl818_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) | + (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8); - save_flags(flags); - cli(); - val = CMOS_READ(RTC_FREQ_SELECT) & 0xf0; - val |= (16 - tmp); - CMOS_WRITE(val, RTC_FREQ_SELECT); - restore_flags(flags); - return rtc_freq; + return insn->n; } -#endif -/* -============================================================================== - Free any resources that we have claimed -*/ -static void free_resources(struct comedi_device *dev) +static int pcl818_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - /* printk("free_resource()\n"); */ - if (dev->private) { - pcl818_ai_cancel(dev, devpriv->sub_ai); - pcl818_reset(dev); - if (devpriv->dma) - free_dma(devpriv->dma); - if (devpriv->dmabuf[0]) - free_pages(devpriv->dmabuf[0], devpriv->dmapages[0]); - if (devpriv->dmabuf[1]) - free_pages(devpriv->dmabuf[1], devpriv->dmapages[1]); -#ifdef unused - if (devpriv->rtc_irq) - free_irq(devpriv->rtc_irq, dev); - if ((devpriv->dma_rtc) && (RTC_lock == 1)) { - if (devpriv->rtc_iobase) - release_region(devpriv->rtc_iobase, - devpriv->rtc_iosize); - } - if (devpriv->dma_rtc) - RTC_lock--; -#endif + if (comedi_dio_update_state(s, data)) { + outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG); + outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG); } - if (dev->irq) - free_irq(dev->irq, dev); - if (dev->iobase) - release_region(dev->iobase, devpriv->io_range); - /* printk("free_resource() end\n"); */ -} - -/* -============================================================================== + data[1] = s->state; - Initialization + return insn->n; +} -*/ -static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static void pcl818_reset(struct comedi_device *dev) { - int ret; - unsigned long iobase; - unsigned int irq; - int dma; - unsigned long pages; - struct comedi_subdevice *s; + const struct pcl818_board *board = comedi_board(dev); + unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE; + unsigned int chan; - ret = alloc_private(dev, sizeof(struct pcl818_private)); - if (ret < 0) - return ret; /* Can't alloc mem */ - - /* claim our I/O space */ - iobase = it->options[0]; - printk("comedi%d: pcl818: board=%s, ioport=0x%03lx", - dev->minor, this_board->name, iobase); - devpriv->io_range = this_board->io_range; - if ((this_board->fifo) && (it->options[2] == -1)) { /* we've board with FIFO and we want to use FIFO */ - devpriv->io_range = PCLx1xFIFO_RANGE; - devpriv->usefifo = 1; - } - if (!request_region(iobase, devpriv->io_range, "pcl818")) { - printk("I/O port conflict\n"); - return -EIO; + /* flush and disable the FIFO */ + if (board->has_fifo) { + outb(0, dev->iobase + PCL818_FI_INTCLR); + outb(0, dev->iobase + PCL818_FI_FLUSH); + outb(0, dev->iobase + PCL818_FI_ENABLE); } - dev->iobase = iobase; + /* disable analog input trigger */ + outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG); + pcl818_ai_clear_eoc(dev); - if (pcl818_check(iobase)) { - printk(", I can't detect board. FAIL!\n"); - return -EIO; - } + pcl818_ai_set_chan_range(dev, 0, 0); - /* set up some name stuff */ - dev->board_name = this_board->name; - /* grab our IRQ */ - irq = 0; - if (this_board->IRQbits != 0) { /* board support IRQ */ - irq = it->options[1]; - if (irq) { /* we want to use IRQ */ - if (((1 << irq) & this_board->IRQbits) == 0) { - printk - (", IRQ %u is out of allowed range, DISABLING IT", - irq); - irq = 0; /* Bad IRQ */ - } else { - if (request_irq - (irq, interrupt_pcl818, 0, "pcl818", dev)) { - printk - (", unable to allocate IRQ %u, DISABLING IT", - irq); - irq = 0; /* Can't use IRQ */ - } else { - printk(", irq=%u", irq); - } - } - } - } + /* stop pacer */ + outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG); + i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY); - dev->irq = irq; - if (irq) { - devpriv->irq_free = 1; - } /* 1=we have allocated irq */ - else { - devpriv->irq_free = 0; - } - devpriv->irq_blocked = 0; /* number of subdevice which use IRQ */ - devpriv->ai_mode = 0; /* mode of irq */ - -#ifdef unused - /* grab RTC for DMA operations */ - devpriv->dma_rtc = 0; - if (it->options[2] > 0) { /* we want to use DMA */ - if (RTC_lock == 0) { - if (!request_region(RTC_PORT(0), RTC_IO_EXTENT, - "pcl818 (RTC)")) - goto no_rtc; - } - devpriv->rtc_iobase = RTC_PORT(0); - devpriv->rtc_iosize = RTC_IO_EXTENT; - RTC_lock++; - if (!request_irq(RTC_IRQ, interrupt_pcl818_ai_mode13_dma_rtc, 0, - "pcl818 DMA (RTC)", dev)) { - devpriv->dma_rtc = 1; - devpriv->rtc_irq = RTC_IRQ; - printk(", dma_irq=%u", devpriv->rtc_irq); - } else { - RTC_lock--; - if (RTC_lock == 0) { - if (devpriv->rtc_iobase) - release_region(devpriv->rtc_iobase, - devpriv->rtc_iosize); - } - devpriv->rtc_iobase = 0; - devpriv->rtc_iosize = 0; - } + /* set analog output channels to 0V */ + for (chan = 0; chan < board->n_aochan; chan++) { + outb(0, dev->iobase + PCL818_AO_LSB_REG(chan)); + outb(0, dev->iobase + PCL818_AO_MSB_REG(chan)); } -no_rtc: -#endif - /* grab our DMA */ - dma = 0; - devpriv->dma = dma; - if ((devpriv->irq_free == 0) && (devpriv->dma_rtc == 0)) - goto no_dma; /* if we haven't IRQ, we can't use DMA */ - if (this_board->DMAbits != 0) { /* board support DMA */ - dma = it->options[2]; - if (dma < 1) - goto no_dma; /* DMA disabled */ - if (((1 << dma) & this_board->DMAbits) == 0) { - printk(", DMA is out of allowed range, FAIL!\n"); - return -EINVAL; /* Bad DMA */ - } - ret = request_dma(dma, "pcl818"); - if (ret) { - printk(", unable to allocate DMA %u, FAIL!\n", dma); - return -EBUSY; /* DMA isn't free */ - } - devpriv->dma = dma; - printk(", dma=%u", dma); - pages = 2; /* we need 16KB */ - devpriv->dmabuf[0] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[0]) { - printk(", unable to allocate DMA buffer, FAIL!\n"); - /* maybe experiment with try_to_free_pages() will help .... */ - return -EBUSY; /* no buffer :-( */ + /* set all digital outputs low */ + outb(0, dev->iobase + PCL818_DO_DI_MSB_REG); + outb(0, dev->iobase + PCL818_DO_DI_LSB_REG); +} + +static void pcl818_set_ai_range_table(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_devconfig *it) +{ + const struct pcl818_board *board = comedi_board(dev); + + /* default to the range table from the boardinfo */ + s->range_table = board->ai_range_type; + + /* now check the user config option based on the boardtype */ + if (board->is_818) { + if (it->options[4] == 1 || it->options[4] == 10) { + /* secondary range list jumper selectable */ + s->range_table = &range_pcl818l_h_ai; } - devpriv->dmapages[0] = pages; - devpriv->hwdmaptr[0] = virt_to_bus((void *)devpriv->dmabuf[0]); - devpriv->hwdmasize[0] = (1 << pages) * PAGE_SIZE; - /* printk("%d %d %ld, ",devpriv->dmapages[0],devpriv->hwdmasize[0],PAGE_SIZE); */ - if (devpriv->dma_rtc == 0) { /* we must do duble buff :-( */ - devpriv->dmabuf[1] = __get_dma_pages(GFP_KERNEL, pages); - if (!devpriv->dmabuf[1]) { - printk - (", unable to allocate DMA buffer, FAIL!\n"); - return -EBUSY; - } - devpriv->dmapages[1] = pages; - devpriv->hwdmaptr[1] = - virt_to_bus((void *)devpriv->dmabuf[1]); - devpriv->hwdmasize[1] = (1 << pages) * PAGE_SIZE; + } else { + switch (it->options[4]) { + case 0: + s->range_table = &range_bipolar10; + break; + case 1: + s->range_table = &range_bipolar5; + break; + case 2: + s->range_table = &range_bipolar2_5; + break; + case 3: + s->range_table = &range718_bipolar1; + break; + case 4: + s->range_table = &range718_bipolar0_5; + break; + case 6: + s->range_table = &range_unipolar10; + break; + case 7: + s->range_table = &range_unipolar5; + break; + case 8: + s->range_table = &range718_unipolar2; + break; + case 9: + s->range_table = &range718_unipolar1; + break; + default: + s->range_table = &range_unknown; + break; } } +} + +static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + const struct pcl818_board *board = comedi_board(dev); + struct pcl818_private *devpriv; + struct comedi_subdevice *s; + int ret; + int i; -no_dma: + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = alloc_subdevices(dev, 4); - if (ret < 0) + ret = comedi_request_region(dev, it->options[0], + board->has_fifo ? 0x20 : 0x10); + if (ret) return ret; - s = dev->subdevices + 0; - if (!this_board->n_aichan_se) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_AI; - devpriv->sub_ai = s; - s->subdev_flags = SDF_READABLE; - if (check_single_ended(dev->iobase)) { - s->n_chan = this_board->n_aichan_se; - s->subdev_flags |= SDF_COMMON | SDF_GROUND; - printk(", %dchans S.E. DAC", s->n_chan); - } else { - s->n_chan = this_board->n_aichan_diff; - s->subdev_flags |= SDF_DIFF; - printk(", %dchans DIFF DAC", s->n_chan); - } - s->maxdata = this_board->ai_maxdata; - s->len_chanlist = s->n_chan; - s->range_table = this_board->ai_range_type; - s->cancel = pcl818_ai_cancel; - s->insn_read = pcl818_ai_insn_read; - if ((irq) || (devpriv->dma_rtc)) { - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->do_cmdtest = ai_cmdtest; - s->do_cmd = ai_cmd; + /* we can use IRQ 2-7 for async command support */ + if (it->options[1] >= 2 && it->options[1] <= 7) { + ret = request_irq(it->options[1], pcl818_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; + } + + /* should we use the FIFO? */ + if (dev->irq && board->has_fifo && it->options[2] == -1) + devpriv->usefifo = 1; + + /* we need an IRQ to do DMA on channel 3 or 1 */ + if (dev->irq && board->has_dma && + (it->options[2] == 3 || it->options[2] == 1)) { + ret = request_dma(it->options[2], dev->board_name); + if (ret) { + dev_err(dev->class_dev, + "unable to request DMA channel %d\n", + it->options[2]); + return -EBUSY; } - if (this_board->is_818) { - if ((it->options[4] == 1) || (it->options[4] == 10)) - s->range_table = &range_pcl818l_h_ai; /* secondary range list jumper selectable */ - } else { - switch (it->options[4]) { - case 0: - s->range_table = &range_bipolar10; - break; - case 1: - s->range_table = &range_bipolar5; - break; - case 2: - s->range_table = &range_bipolar2_5; - break; - case 3: - s->range_table = &range718_bipolar1; - break; - case 4: - s->range_table = &range718_bipolar0_5; - break; - case 6: - s->range_table = &range_unipolar10; - break; - case 7: - s->range_table = &range_unipolar5; - break; - case 8: - s->range_table = &range718_unipolar2; - break; - case 9: - s->range_table = &range718_unipolar1; - break; - default: - s->range_table = &range_unknown; - break; - } + devpriv->dma = it->options[2]; + + devpriv->dmapages = 2; /* we need 16KB */ + devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE; + + for (i = 0; i < 2; i++) { + unsigned long dmabuf; + + dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages); + if (!dmabuf) + return -ENOMEM; + + devpriv->dmabuf[i] = dmabuf; + devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf); } } - s = dev->subdevices + 1; - if (!this_board->n_aochan) { - s->type = COMEDI_SUBD_UNUSED; + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE; + if (check_single_ended(dev->iobase)) { + s->n_chan = 16; + s->subdev_flags |= SDF_COMMON | SDF_GROUND; } else { - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - 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->ao_range_type; - s->insn_read = pcl818_ao_insn_read; - s->insn_write = pcl818_ao_insn_write; -#ifdef unused -#ifdef PCL818_MODE13_AO - if (irq) { - s->trig[1] = pcl818_ao_mode1; - s->trig[3] = pcl818_ao_mode3; - } -#endif -#endif - if (this_board->is_818) { + s->n_chan = 8; + s->subdev_flags |= SDF_DIFF; + } + s->maxdata = 0x0fff; + + pcl818_set_ai_range_table(dev, s, it); + + s->insn_read = pcl818_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->do_cmdtest = ai_cmdtest; + s->do_cmd = pcl818_ai_cmd; + s->cancel = pcl818_ai_cancel; + } + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + if (board->n_aochan) { + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND; + s->n_chan = board->n_aochan; + s->maxdata = 0x0fff; + s->range_table = &range_unipolar5; + s->insn_read = pcl818_ao_insn_read; + s->insn_write = pcl818_ao_insn_write; + if (board->is_818) { if ((it->options[4] == 1) || (it->options[4] == 10)) s->range_table = &range_unipolar10; if (it->options[4] == 2) @@ -1987,67 +1184,75 @@ no_dma: if (it->options[5] == 2) s->range_table = &range_unknown; } - } - - s = dev->subdevices + 2; - if (!this_board->n_dichan) { - s->type = COMEDI_SUBD_UNUSED; } else { - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = this_board->n_dichan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dichan; - s->range_table = &range_digital; - s->insn_bits = pcl818_di_insn_bits; - } - - s = dev->subdevices + 3; - if (!this_board->n_dochan) { - s->type = COMEDI_SUBD_UNUSED; - } else { - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = this_board->n_dochan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dochan; - s->range_table = &range_digital; - s->insn_bits = pcl818_do_insn_bits; - } + s->type = COMEDI_SUBD_UNUSED; + } + + /* Digital Input subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_di_insn_bits; + + /* Digital Output subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcl818_do_insn_bits; /* select 1/10MHz oscilator */ - if ((it->options[3] == 0) || (it->options[3] == 10)) { - devpriv->i8253_osc_base = 100; - } else { - devpriv->i8253_osc_base = 1000; - } + if ((it->options[3] == 0) || (it->options[3] == 10)) + devpriv->i8253_osc_base = I8254_OSC_BASE_10MHZ; + else + devpriv->i8253_osc_base = I8254_OSC_BASE_1MHZ; /* max sampling speed */ - devpriv->ns_min = this_board->ns_min; + devpriv->ns_min = board->ns_min; - if (!this_board->is_818) { + if (!board->is_818) { if ((it->options[6] == 1) || (it->options[6] == 100)) devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */ } pcl818_reset(dev); - printk("\n"); - return 0; } -/* -============================================================================== - Removes device - */ -static int pcl818_detach(struct comedi_device *dev) +static void pcl818_detach(struct comedi_device *dev) { - /* printk("comedi%d: pcl818: remove\n", dev->minor); */ - free_resources(dev); - return 0; + struct pcl818_private *devpriv = dev->private; + + if (devpriv) { + pcl818_ai_cancel(dev, dev->read_subdev); + pcl818_reset(dev); + if (devpriv->dma) + free_dma(devpriv->dma); + if (devpriv->dmabuf[0]) + free_pages(devpriv->dmabuf[0], devpriv->dmapages); + if (devpriv->dmabuf[1]) + free_pages(devpriv->dmabuf[1], devpriv->dmapages); + } + comedi_legacy_detach(dev); } +static struct comedi_driver pcl818_driver = { + .driver_name = "pcl818", + .module = THIS_MODULE, + .attach = pcl818_attach, + .detach = pcl818_detach, + .board_name = &boardtypes[0].name, + .num_names = ARRAY_SIZE(boardtypes), + .offset = sizeof(struct pcl818_board), +}; +module_comedi_driver(pcl818_driver); + MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index f5c0bd17684..53e73737a90 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -28,11 +28,9 @@ Copy/pasted/hacked from pcm724.c * struct comedi_insn */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/delay.h> - #include "8255.h" #define PCM3724_SIZE 16 @@ -62,68 +60,21 @@ Copy/pasted/hacked from pcm724.c #define CR_A_MODE(a) ((a)<<5) #define CR_CW 0x80 -static int pcm3724_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcm3724_detach(struct comedi_device *dev); - -struct pcm3724_board { - const char *name; /* driver name */ - int dio; /* num of DIO */ - int numofports; /* num of 8255 subdevices */ - unsigned int IRQbits; /* allowed interrupts */ - unsigned int io_range; /* len of IO space */ -}; - /* used to track configured dios */ struct priv_pcm3724 { int dio_1; int dio_2; }; -static const struct pcm3724_board boardtypes[] = { - {"pcm3724", 48, 2, 0x00fc, PCM3724_SIZE,}, -}; - -#define n_boardtypes (sizeof(boardtypes)/sizeof(struct pcm3724_board)) -#define this_board ((const struct pcm3724_board *)dev->board_ptr) - -static struct comedi_driver driver_pcm3724 = { - .driver_name = "pcm3724", - .module = THIS_MODULE, - .attach = pcm3724_attach, - .detach = pcm3724_detach, - .board_name = &boardtypes[0].name, - .num_names = n_boardtypes, - .offset = sizeof(struct pcm3724_board), -}; - -static int __init driver_pcm3724_init_module(void) -{ - return comedi_driver_register(&driver_pcm3724); -} - -static void __exit driver_pcm3724_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcm3724); -} - -module_init(driver_pcm3724_init_module); -module_exit(driver_pcm3724_cleanup_module); - -/* (setq c-basic-offset 8) */ - static int subdev_8255_cb(int dir, int port, int data, unsigned long arg) { unsigned long iobase = arg; unsigned char inbres; - /* printk("8255cb %d %d %d %lx\n", dir,port,data,arg); */ if (dir) { - /* printk("8255 cb outb(%x, %lx)\n", data, iobase+port); */ outb(data, iobase + port); return 0; } else { inbres = inb(iobase + port); - /* printk("8255 cb inb(%lx) = %x\n", iobase+port, inbres); */ return inbres; } } @@ -155,6 +106,8 @@ static int compute_buffer(int config, int devno, struct comedi_subdevice *s) static void do_3724_config(struct comedi_device *dev, struct comedi_subdevice *s, int chanspec) { + struct comedi_subdevice *s_dio1 = &dev->subdevices[0]; + struct comedi_subdevice *s_dio2 = &dev->subdevices[1]; int config; int buffer_config; unsigned long port_8255_cfg; @@ -172,17 +125,15 @@ static void do_3724_config(struct comedi_device *dev, if (!(s->io_bits & 0xff0000)) config |= CR_C_IO; - buffer_config = compute_buffer(0, 0, dev->subdevices); - buffer_config = compute_buffer(buffer_config, 1, (dev->subdevices) + 1); + buffer_config = compute_buffer(0, 0, s_dio1); + buffer_config = compute_buffer(buffer_config, 1, s_dio2); - if (s == dev->subdevices) + if (s == s_dio1) port_8255_cfg = dev->iobase + _8255_CR; else port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR; outb(buffer_config, dev->iobase + 8); /* update buffer register */ - /* printk("pcm3724 buffer_config (%lx) %d, %x\n", - dev->iobase + _8255_CR, chanspec, buffer_config); */ outb(config, port_8255_cfg); } @@ -190,17 +141,17 @@ static void do_3724_config(struct comedi_device *dev, static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s, int chanspec) { + struct priv_pcm3724 *priv = dev->private; + struct comedi_subdevice *s_dio1 = &dev->subdevices[0]; unsigned int mask; int gatecfg; - struct priv_pcm3724 *priv; gatecfg = 0; - priv = dev->private; mask = 1 << CR_CHAN(chanspec); - if (s == dev->subdevices) /* subdev 0 */ + if (s == s_dio1) priv->dio_1 |= mask; - else /* subdev 1 */ + else priv->dio_2 |= mask; if (priv->dio_1 & 0xff0000) @@ -221,103 +172,75 @@ static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s, if (priv->dio_2 & 0xff) gatecfg |= GATE_A1; - /* printk("gate control %x\n", gatecfg); */ outb(gatecfg, dev->iobase + 9); } /* overriding the 8255 insn config */ static int subdev_3724_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); unsigned int mask; - unsigned int bits; - - mask = 1 << CR_CHAN(insn->chanspec); - if (mask & 0x0000ff) - bits = 0x0000ff; - else if (mask & 0x00ff00) - bits = 0x00ff00; - else if (mask & 0x0f0000) - bits = 0x0f0000; + int ret; + + if (chan < 8) + mask = 0x0000ff; + else if (chan < 16) + mask = 0x00ff00; + else if (chan < 20) + mask = 0x0f0000; else - bits = 0xf00000; - - switch (data[0]) { - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~bits; - break; - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= bits; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + mask = 0xf00000; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; do_3724_config(dev, s, insn->chanspec); enable_chan(dev, s, insn->chanspec); - return 1; + + return insn->n; } static int pcm3724_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - unsigned long iobase; - unsigned int iorange; - int ret, i, n_subdevices; - - iobase = it->options[0]; - iorange = this_board->io_range; + struct priv_pcm3724 *priv; + struct comedi_subdevice *s; + int ret, i; - ret = alloc_private(dev, sizeof(struct priv_pcm3724)); - if (ret < 0) + priv = comedi_alloc_devpriv(dev, sizeof(*priv)); + if (!priv) return -ENOMEM; - ((struct priv_pcm3724 *)(dev->private))->dio_1 = 0; - ((struct priv_pcm3724 *)(dev->private))->dio_2 = 0; - - printk(KERN_INFO "comedi%d: pcm3724: board=%s, 0x%03lx ", dev->minor, - this_board->name, iobase); - if (!iobase || !request_region(iobase, iorange, "pcm3724")) { - printk("I/O port conflict\n"); - return -EIO; - } - - dev->iobase = iobase; - dev->board_name = this_board->name; - printk(KERN_INFO "\n"); - - n_subdevices = this_board->numofports; + ret = comedi_request_region(dev, it->options[0], PCM3724_SIZE); + if (ret) + return ret; - ret = alloc_subdevices(dev, n_subdevices); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 2); + if (ret) return ret; for (i = 0; i < dev->n_subdevices; i++) { - subdev_8255_init(dev, dev->subdevices + i, subdev_8255_cb, - (unsigned long)(dev->iobase + SIZE_8255 * i)); - ((dev->subdevices) + i)->insn_config = subdev_3724_insn_config; + s = &dev->subdevices[i]; + ret = subdev_8255_init(dev, s, subdev_8255_cb, + dev->iobase + SIZE_8255 * i); + if (ret) + return ret; + s->insn_config = subdev_3724_insn_config; } return 0; } -static int pcm3724_detach(struct comedi_device *dev) -{ - int i; - - if (dev->subdevices) { - for (i = 0; i < dev->n_subdevices; i++) - subdev_8255_cleanup(dev, dev->subdevices + i); - } - if (dev->iobase) - release_region(dev->iobase, this_board->io_range); - - return 0; -} +static struct comedi_driver pcm3724_driver = { + .driver_name = "pcm3724", + .module = THIS_MODULE, + .attach = pcm3724_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(pcm3724_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c deleted file mode 100644 index bada6b236ff..00000000000 --- a/drivers/staging/comedi/drivers/pcm3730.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - * comedi/drivers/pcm3730.c - * Driver for PCM3730 and clones - * Blaine Lee - * from pcl725 by David S. - */ -/* -Driver: pcm3730 -Description: PCM3730 -Author: Blaine Lee -Devices: [Advantech] PCM-3730 (pcm3730) -Status: unknown - -Configuration options: - [0] - I/O port base -*/ - -#include "../comedidev.h" - -#include <linux/ioport.h> - -#define PCM3730_SIZE 4 /* consecutive io port addresses */ - -#define PCM3730_DOA 0 /* offsets for each port */ -#define PCM3730_DOB 2 -#define PCM3730_DOC 3 -#define PCM3730_DIA 0 -#define PCM3730_DIB 2 -#define PCM3730_DIC 3 - -static int pcm3730_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcm3730_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcm3730 = { - .driver_name = "pcm3730", - .module = THIS_MODULE, - .attach = pcm3730_attach, - .detach = pcm3730_detach, -}; - -static int __init driver_pcm3730_init_module(void) -{ - return comedi_driver_register(&driver_pcm3730); -} - -static void __exit driver_pcm3730_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcm3730); -} - -module_init(driver_pcm3730_init_module); -module_exit(driver_pcm3730_cleanup_module); - -static int pcm3730_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - outb(s->state, dev->iobase + (unsigned long)(s->private)); - } - data[1] = s->state; - - return 2; -} - -static int pcm3730_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - data[1] = inb(dev->iobase + (unsigned long)(s->private)); - return 2; -} - -static int pcm3730_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: pcm3730: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, PCM3730_SIZE, "pcm3730")) { - printk("I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - dev->board_name = "pcm3730"; - dev->iobase = dev->iobase; - dev->irq = 0; - - if (alloc_subdevices(dev, 6) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_do_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DOA; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_do_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DOB; - - s = dev->subdevices + 2; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_do_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DOC; - - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_di_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DIA; - - s = dev->subdevices + 4; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_di_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DIB; - - s = dev->subdevices + 5; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->maxdata = 1; - s->n_chan = 8; - s->insn_bits = pcm3730_di_insn_bits; - s->range_table = &range_digital; - s->private = (void *)PCM3730_DIC; - - printk(KERN_INFO "\n"); - - return 0; -} - -static int pcm3730_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pcm3730: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, PCM3730_SIZE); - - return 0; -} - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcm_common.c b/drivers/staging/comedi/drivers/pcm_common.c deleted file mode 100644 index 474af7bc6c8..00000000000 --- a/drivers/staging/comedi/drivers/pcm_common.c +++ /dev/null @@ -1,115 +0,0 @@ -#include "../comedidev.h" -#include "pcm_common.h" - -/* - * 'do_cmdtest' function for an 'INTERRUPT' subdevice. This is for - * the PCM drivers. - */ -int comedi_pcm_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - int err = 0; - unsigned int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= (TRIG_NOW | TRIG_INT); - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= (TRIG_COUNT | TRIG_NONE); - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) - return 1; - - /* step 2: make sure trigger sources are unique and - * mutually compatible */ - - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; - - if (err) - return 2; - - /* step 3: make sure arguments are trivially compatible */ - - /* cmd->start_src == TRIG_NOW || cmd->start_src == TRIG_INT */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - - /* cmd->scan_begin_src == TRIG_EXT */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - - /* cmd->convert_src == TRIG_NOW */ - if (cmd->convert_arg != 0) { - cmd->convert_arg = 0; - err++; - } - - /* cmd->scan_end_src == TRIG_COUNT */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - - switch (cmd->stop_src) { - case TRIG_COUNT: - /* any count allowed */ - break; - case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - break; - default: - break; - } - - if (err) - return 3; - - /* step 4: fix up any arguments */ - - /* if (err) return 4; */ - - return 0; -} -EXPORT_SYMBOL(comedi_pcm_cmdtest); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcm_common.h b/drivers/staging/comedi/drivers/pcm_common.h deleted file mode 100644 index cd4840c1144..00000000000 --- a/drivers/staging/comedi/drivers/pcm_common.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _comedi_common_H -#define _comedi_common_H - -extern int comedi_pcm_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -#endif diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index 23b3d777340..87c61d9b11d 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -1,52 +1,45 @@ /* - comedi/drivers/pcmad.c - Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * pcmad.c + * Hardware driver for Winsystems PCM-A/D12 and PCM-A/D16 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ -*/ /* -Driver: pcmad -Description: Winsystems PCM-A/D12, PCM-A/D16 -Author: ds -Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16) -Status: untested - -This driver was written on a bet that I couldn't write a driver -in less than 2 hours. I won the bet, but never got paid. =( - -Configuration options: - [0] - I/O port base - [1] - unused - [2] - Analog input reference - 0 = single ended - 1 = differential - [3] - Analog input encoding (must match jumpers) - 0 = straight binary - 1 = two's complement -*/ - -#include <linux/interrupt.h> -#include "../comedidev.h" - -#include <linux/ioport.h> + * Driver: pcmad + * Description: Winsystems PCM-A/D12, PCM-A/D16 + * Devices: (Winsystems) PCM-A/D12 [pcmad12] + * (Winsystems) PCM-A/D16 [pcmad16] + * Author: ds + * Status: untested + * + * This driver was written on a bet that I couldn't write a driver + * in less than 2 hours. I won the bet, but never got paid. =( + * + * Configuration options: + * [0] - I/O port base + * [1] - IRQ (unused) + * [2] - Analog input reference (must match jumpers) + * 0 = single-ended (16 channels) + * 1 = differential (8 channels) + * [3] - Analog input encoding (must match jumpers) + * 0 = straight binary (0-5V input range) + * 1 = two's complement (+-10V input range) + */ -#define PCMAD_SIZE 4 +#include <linux/module.h> +#include "../comedidev.h" #define PCMAD_STATUS 0 #define PCMAD_LSB 1 @@ -55,138 +48,111 @@ Configuration options: struct pcmad_board_struct { const char *name; - int n_ai_bits; + unsigned int ai_maxdata; }; + static const struct pcmad_board_struct pcmad_boards[] = { { - .name = "pcmad12", - .n_ai_bits = 12, - }, - { - .name = "pcmad16", - .n_ai_bits = 16, - }, -}; - -#define this_board ((const struct pcmad_board_struct *)(dev->board_ptr)) -#define n_pcmad_boards ARRAY_SIZE(pcmad_boards) - -struct pcmad_priv_struct { - int differential; - int twos_comp; -}; -#define devpriv ((struct pcmad_priv_struct *)dev->private) - -static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int pcmad_detach(struct comedi_device *dev); -static struct comedi_driver driver_pcmad = { - .driver_name = "pcmad", - .module = THIS_MODULE, - .attach = pcmad_attach, - .detach = pcmad_detach, - .board_name = &pcmad_boards[0].name, - .num_names = n_pcmad_boards, - .offset = sizeof(pcmad_boards[0]), + .name = "pcmad12", + .ai_maxdata = 0x0fff, + }, { + .name = "pcmad16", + .ai_maxdata = 0xffff, + }, }; -static int __init driver_pcmad_init_module(void) +static int pcmad_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - return comedi_driver_register(&driver_pcmad); -} + unsigned int status; -static void __exit driver_pcmad_cleanup_module(void) -{ - comedi_driver_unregister(&driver_pcmad); + status = inb(dev->iobase + PCMAD_STATUS); + if ((status & 0x3) == 0x3) + return 0; + return -EBUSY; } -module_init(driver_pcmad_init_module); -module_exit(driver_pcmad_cleanup_module); - -#define TIMEOUT 100 - static int pcmad_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int ret; int i; - int chan; - int n; - chan = CR_CHAN(insn->chanspec); - - for (n = 0; n < insn->n; n++) { + for (i = 0; i < insn->n; i++) { outb(chan, dev->iobase + PCMAD_CONVERT); - for (i = 0; i < TIMEOUT; i++) { - if ((inb(dev->iobase + PCMAD_STATUS) & 0x3) == 0x3) - break; + ret = comedi_timeout(dev, s, insn, pcmad_ai_eoc, 0); + if (ret) + return ret; + + val = inb(dev->iobase + PCMAD_LSB) | + (inb(dev->iobase + PCMAD_MSB) << 8); + + /* data is shifted on the pcmad12, fix it */ + if (s->maxdata == 0x0fff) + val >>= 4; + + if (comedi_range_is_bipolar(s, range)) { + /* munge the two's complement value */ + val ^= ((s->maxdata + 1) >> 1); } - data[n] = inb(dev->iobase + PCMAD_LSB); - data[n] |= (inb(dev->iobase + PCMAD_MSB) << 8); - if (devpriv->twos_comp) - data[n] ^= (1 << (this_board->n_ai_bits - 1)); + data[i] = val; } - return n; + return insn->n; } -/* - * options: - * 0 i/o base - * 1 unused - * 2 0=single ended 1=differential - * 3 0=straight binary 1=two's comp - */ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int ret; + const struct pcmad_board_struct *board = comedi_board(dev); struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: pcmad: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, PCMAD_SIZE, "pcmad")) { - printk(KERN_CONT "I/O port conflict\n"); - return -EIO; - } - printk(KERN_CONT "\n"); - dev->iobase = iobase; + int ret; - ret = alloc_subdevices(dev, 1); - if (ret < 0) + ret = comedi_request_region(dev, it->options[0], 0x04); + if (ret) return ret; - ret = alloc_private(dev, sizeof(struct pcmad_priv_struct)); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 1); + if (ret) return ret; - dev->board_name = this_board->name; - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | AREF_GROUND; - s->n_chan = 16; /* XXX */ - s->len_chanlist = 1; - s->insn_read = pcmad_ai_insn_read; - s->maxdata = (1 << this_board->n_ai_bits) - 1; - s->range_table = &range_unknown; + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + if (it->options[1]) { + /* 8 differential channels */ + s->subdev_flags = SDF_READABLE | AREF_DIFF; + s->n_chan = 8; + } else { + /* 16 single-ended channels */ + s->subdev_flags = SDF_READABLE | AREF_GROUND; + s->n_chan = 16; + } + s->len_chanlist = 1; + s->maxdata = board->ai_maxdata; + s->range_table = it->options[2] ? &range_bipolar10 : &range_unipolar5; + s->insn_read = pcmad_ai_insn_read; return 0; } -static int pcmad_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: pcmad: remove\n", dev->minor); - - if (dev->irq) - free_irq(dev->irq, dev); - - if (dev->iobase) - release_region(dev->iobase, PCMAD_SIZE); - - return 0; -} +static struct comedi_driver pcmad_driver = { + .driver_name = "pcmad", + .module = THIS_MODULE, + .attach = pcmad_attach, + .detach = comedi_legacy_detach, + .board_name = &pcmad_boards[0].name, + .num_names = ARRAY_SIZE(pcmad_boards), + .offset = sizeof(pcmad_boards[0]), +}; +module_comedi_driver(pcmad_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c index 0e9ffa28d74..1c7a135c91d 100644 --- a/drivers/staging/comedi/drivers/pcmda12.c +++ b/drivers/staging/comedi/drivers/pcmda12.c @@ -1,322 +1,175 @@ /* - comedi/drivers/pcmda12.c - Driver for Winsystems PC-104 based PCM-D/A-12 8-channel AO board. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * pcmda12.c + * Driver for Winsystems PC-104 based PCM-D/A-12 8-channel AO board. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ /* -Driver: pcmda12 -Description: A driver for the Winsystems PCM-D/A-12 -Devices: [Winsystems] PCM-D/A-12 (pcmda12) -Author: Calin Culianu <calin@ajvar.org> -Updated: Fri, 13 Jan 2006 12:01:01 -0500 -Status: works - -A driver for the relatively straightforward-to-program PCM-D/A-12. -This board doesn't support commands, and the only way to set its -analog output range is to jumper the board. As such, -comedi_data_write() ignores the range value specified. - -The board uses 16 consecutive I/O addresses starting at the I/O port -base address. Each address corresponds to the LSB then MSB of a -particular channel from 0-7. - -Note that the board is not ISA-PNP capable and thus -needs the I/O port comedi_config parameter. - -Note that passing a nonzero value as the second config option will -enable "simultaneous xfer" mode for this board, in which AO writes -will not take effect until a subsequent read of any AO channel. This -is so that one can speed up programming by preloading all AO registers -with values before simultaneously setting them to take effect with one -read command. - -Configuration Options: - [0] - I/O port base address - [1] - Do Simultaneous Xfer (see description) -*/ + * Driver: pcmda12 + * Description: A driver for the Winsystems PCM-D/A-12 + * Devices: (Winsystems) PCM-D/A-12 [pcmda12] + * Author: Calin Culianu <calin@ajvar.org> + * Updated: Fri, 13 Jan 2006 12:01:01 -0500 + * Status: works + * + * A driver for the relatively straightforward-to-program PCM-D/A-12. + * This board doesn't support commands, and the only way to set its + * analog output range is to jumper the board. As such, + * comedi_data_write() ignores the range value specified. + * + * The board uses 16 consecutive I/O addresses starting at the I/O port + * base address. Each address corresponds to the LSB then MSB of a + * particular channel from 0-7. + * + * Note that the board is not ISA-PNP capable and thus needs the I/O + * port comedi_config parameter. + * + * Note that passing a nonzero value as the second config option will + * enable "simultaneous xfer" mode for this board, in which AO writes + * will not take effect until a subsequent read of any AO channel. This + * is so that one can speed up programming by preloading all AO registers + * with values before simultaneously setting them to take effect with one + * read command. + * + * Configuration Options: + * [0] - I/O port base address + * [1] - Do Simultaneous Xfer (see description) + */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/pci.h> /* for PCI devices */ - -#define SDEV_NO ((int)(s - dev->subdevices)) -#define CHANS 8 -#define IOSIZE 16 -#define LSB(x) ((unsigned char)((x) & 0xff)) -#define MSB(x) ((unsigned char)((((unsigned short)(x))>>8) & 0xff)) -#define LSB_PORT(chan) (dev->iobase + (chan)*2) -#define MSB_PORT(chan) (LSB_PORT(chan)+1) -#define BITS 12 - -/* - * Bords - */ -struct pcmda12_board { - const char *name; -}; - -/* note these have no effect and are merely here for reference.. - these are configured by jumpering the board! */ +/* AI range is not configurable, it's set by jumpers on the board */ static const struct comedi_lrange pcmda12_ranges = { - 3, - { - UNI_RANGE(5), UNI_RANGE(10), BIP_RANGE(5) - } -}; - -static const struct pcmda12_board pcmda12_boards[] = { - { - .name = "pcmda12", - }, + 3, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5) + } }; -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct pcmda12_board *)dev->board_ptr) - struct pcmda12_private { - - unsigned int ao_readback[CHANS]; + unsigned int ao_readback[8]; int simultaneous_xfer_mode; }; -#define devpriv ((struct pcmda12_private *)(dev->private)) - -/* - * 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 int pcmda12_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcmda12_detach(struct comedi_device *dev); - -static void zero_chans(struct comedi_device *dev); - -static struct comedi_driver driver = { - .driver_name = "pcmda12", - .module = THIS_MODULE, - .attach = pcmda12_attach, - .detach = pcmda12_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 pcmda12_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 = &pcmda12_boards[0].name, - .offset = sizeof(struct pcmda12_board), - .num_names = ARRAY_SIZE(pcmda12_boards), -}; - -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pcmda12_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pcmda12_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct comedi_subdevice *s; - unsigned long iobase; - - iobase = it->options[0]; - printk(KERN_INFO - "comedi%d: %s: io: %lx %s ", dev->minor, driver.driver_name, - iobase, it->options[1] ? "simultaneous xfer mode enabled" : ""); + struct pcmda12_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + unsigned long ioreg = dev->iobase + (chan * 2); + int i; - if (!request_region(iobase, IOSIZE, driver.driver_name)) { - printk("I/O port conflict\n"); - return -EIO; + for (i = 0; i < insn->n; ++i) { + val = data[i]; + outb(val & 0xff, ioreg); + outb((val >> 8) & 0xff, ioreg + 1); + + /* + * Initiate transfer if not in simultaneaous xfer + * mode by reading one of the AO registers. + */ + if (!devpriv->simultaneous_xfer_mode) + inb(ioreg); } - dev->iobase = iobase; + devpriv->ao_readback[chan] = val; -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct pcmda12_private)) < 0) { - printk(KERN_ERR "cannot allocate private data structure\n"); - return -ENOMEM; - } + return insn->n; +} - devpriv->simultaneous_xfer_mode = it->options[1]; +static int pcmda12_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcmda12_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - * - * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the - * 96-channel version of the board. + * Initiate simultaneaous xfer mode by reading one of the + * AO registers. All analog outputs will then be updated. */ - if (alloc_subdevices(dev, 1) < 0) { - printk(KERN_ERR "cannot allocate subdevice data structures\n"); - return -ENOMEM; - } + if (devpriv->simultaneous_xfer_mode) + inb(dev->iobase); - s = dev->subdevices; - s->private = NULL; - s->maxdata = (0x1 << BITS) - 1; - s->range_table = &pcmda12_ranges; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = CHANS; - s->insn_write = &ao_winsn; - s->insn_read = &ao_rinsn; - - zero_chans(dev); /* clear out all the registers, basically */ - - printk(KERN_INFO "attached\n"); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; - return 1; + return insn->n; } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pcmda12_detach(struct comedi_device *dev) +static void pcmda12_ao_reset(struct comedi_device *dev, + struct comedi_subdevice *s) { - printk(KERN_INFO - "comedi%d: %s: remove\n", dev->minor, driver.driver_name); - if (dev->iobase) - release_region(dev->iobase, IOSIZE); - return 0; -} - -static void zero_chans(struct comedi_device *dev) -{ /* sets up an - ASIC chip to defaults */ int i; - for (i = 0; i < CHANS; ++i) { -/* /\* do this as one instruction?? *\/ */ -/* outw(0, LSB_PORT(chan)); */ - outb(0, LSB_PORT(i)); - outb(0, MSB_PORT(i)); + + for (i = 0; i < s->n_chan; ++i) { + outb(0, dev->iobase + (i * 2)); + outb(0, dev->iobase + (i * 2) + 1); } - inb(LSB_PORT(0)); /* update chans. */ + /* Initiate transfer by reading one of the AO registers. */ + inb(dev->iobase); } -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcmda12_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { - 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) { - -/* /\* do this as one instruction?? *\/ */ -/* outw(data[i], LSB_PORT(chan)); */ - - /* Need to do this as two instructions due to 8-bit bus?? */ - /* first, load the low byte */ - outb(LSB(data[i]), LSB_PORT(chan)); - /* next, write the high byte */ - outb(MSB(data[i]), MSB_PORT(chan)); - - /* save shadow register */ - devpriv->ao_readback[chan] = data[i]; - - if (!devpriv->simultaneous_xfer_mode) - inb(LSB_PORT(chan)); - } - - /* return the number of samples written */ - return i; -} + struct pcmda12_private *devpriv; + struct comedi_subdevice *s; + int ret; -/* AO subdevices should have a read insn as well as a write insn. + ret = comedi_request_region(dev, it->options[0], 0x10); + if (ret) + return ret; - Usually this means copying a value stored in devpriv->ao_readback. - However, since this driver supports simultaneous xfer then sometimes - this function actually accomplishes work. + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - Simultaneaous xfer mode is accomplished by loading ALL the values - you want for AO in all the channels, then READing off one of the AO - registers to initiate the instantaneous simultaneous update of all - DAC outputs, which makes all AO channels update simultaneously. - This is useful for some control applications, I would imagine. -*/ -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i; - int chan = CR_CHAN(insn->chanspec); + devpriv->simultaneous_xfer_mode = it->options[1]; - for (i = 0; i < insn->n; i++) { - if (devpriv->simultaneous_xfer_mode) - inb(LSB_PORT(chan)); - /* read back shadow register */ - data[i] = devpriv->ao_readback[chan]; - } + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; - return i; -} + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->range_table = &pcmda12_ranges; + s->insn_write = pcmda12_ao_insn_write; + s->insn_read = pcmda12_ao_insn_read; -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_init_module(void) -{ - return comedi_driver_register(&driver); -} + pcmda12_ao_reset(dev, s); -static void __exit driver_cleanup_module(void) -{ - comedi_driver_unregister(&driver); + return 0; } -module_init(driver_init_module); -module_exit(driver_cleanup_module); +static struct comedi_driver pcmda12_driver = { + .driver_name = "pcmda12", + .module = THIS_MODULE, + .attach = pcmda12_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(pcmda12_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index f2e88e57d55..fed7e77e030 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -1,1113 +1,482 @@ /* - comedi/drivers/pcmmio.c - Driver for Winsystems PC-104 based multifunction IO board. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* -Driver: pcmmio -Description: A driver for the PCM-MIO multifunction board -Devices: [Winsystems] PCM-MIO (pcmmio) -Author: Calin Culianu <calin@ajvar.org> -Updated: Wed, May 16 2007 16:21:10 -0500 -Status: works - -A driver for the relatively new PCM-MIO multifunction board from -Winsystems. This board is a PC-104 based I/O board. It contains -four subdevices: - subdevice 0 - 16 channels of 16-bit AI - subdevice 1 - 8 channels of 16-bit AO - subdevice 2 - first 24 channels of the 48 channel of DIO - (with edge-triggered interrupt support) - subdevice 3 - last 24 channels of the 48 channel DIO - (no interrupt support for this bank of channels) - - Some notes: - - Synchronous reads and writes are the only things implemented for AI and AO, - even though the hardware itself can do streaming acquisition, etc. Anyone - want to add asynchronous I/O for AI/AO as a feature? Be my guest... - - Asynchronous I/O for the DIO subdevices *is* implemented, however! They are - basically edge-triggered interrupts for any configuration of the first - 24 DIO-lines. - - Also note that this interrupt support is untested. - - A few words about edge-detection IRQ support (commands on DIO): - - * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ - of the board to the comedi_config command. The board IRQ is not jumpered - but rather configured through software, so any IRQ from 1-15 is OK. - - * Due to the genericity of the comedi API, you need to create a special - comedi_command in order to use edge-triggered interrupts for DIO. - - * Use comedi_commands with TRIG_NOW. Your callback will be called each - time an edge is detected on the specified DIO line(s), and the data - values will be two sample_t's, which should be concatenated to form - one 32-bit unsigned int. This value is the mask of channels that had - edges detected from your channel list. Note that the bits positions - in the mask correspond to positions in your chanlist when you - specified the command and *not* channel id's! - - * To set the polarity of the edge-detection interrupts pass a nonzero value - for either CR_RANGE or CR_AREF for edge-up polarity, or a zero - value for both CR_RANGE and CR_AREF if you want edge-down polarity. - -Configuration Options: - [0] - I/O port base address - [1] - IRQ (optional -- for edge-detect interrupt support only, - leave out if you don't need this feature) -*/ - -#include <linux/interrupt.h> -#include <linux/slab.h> -#include "../comedidev.h" -#include "pcm_common.h" -#include <linux/pci.h> /* for PCI devices */ - -/* This stuff is all from pcmuio.c -- it refers to the DIO subdevices only */ -#define CHANS_PER_PORT 8 -#define PORTS_PER_ASIC 6 -#define INTR_PORTS_PER_ASIC 3 -#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */ -#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT) -#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC) -#define INTR_CHANS_PER_ASIC 24 -#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) -#define MAX_DIO_CHANS (PORTS_PER_ASIC*1*CHANS_PER_PORT) -#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) -#define SDEV_NO ((int)(s - dev->subdevices)) -#define CALC_N_DIO_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) -/* IO Memory sizes */ -#define ASIC_IOSIZE (0x0B) -#define PCMMIO48_IOSIZE ASIC_IOSIZE - -/* Some offsets - these are all in the 16byte IO memory offset from - the base address. Note that there is a paging scheme to swap out - offsets 0x8-0xA using the PAGELOCK register. See the table below. - - Register(s) Pages R/W? Description - -------------------------------------------------------------- - REG_PORTx All R/W Read/Write/Configure IO - REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int. - REG_PAGELOCK All WriteOnly Select a page - REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity - REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int. - REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints. - */ -#define REG_PORT0 0x0 -#define REG_PORT1 0x1 -#define REG_PORT2 0x2 -#define REG_PORT3 0x3 -#define REG_PORT4 0x4 -#define REG_PORT5 0x5 -#define REG_INT_PENDING 0x6 -#define REG_PAGELOCK 0x7 /* - * page selector register, upper 2 bits select - * a page and bits 0-5 are used to 'lock down' - * a particular port above to make it readonly. - */ -#define REG_POL0 0x8 -#define REG_POL1 0x9 -#define REG_POL2 0xA -#define REG_ENAB0 0x8 -#define REG_ENAB1 0x9 -#define REG_ENAB2 0xA -#define REG_INT_ID0 0x8 -#define REG_INT_ID1 0x9 -#define REG_INT_ID2 0xA - -#define NUM_PAGED_REGS 3 -#define NUM_PAGES 4 -#define FIRST_PAGED_REG 0x8 -#define REG_PAGE_BITOFFSET 6 -#define REG_LOCK_BITOFFSET 0 -#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1)) -#define REG_LOCK_MASK (~(REG_PAGE_MASK)) -#define PAGE_POL 1 -#define PAGE_ENAB 2 -#define PAGE_INT_ID 3 - -static int ai_rinsn(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); -static int ao_rinsn(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); -static int ao_winsn(struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - -/* - * 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. + * pcmmio.c + * Driver for Winsystems PC-104 based multifunction IO board. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ -struct pcmmio_board { - const char *name; - const int dio_num_asics; - const int dio_num_ports; - const int total_iosize; - const int ai_bits; - const int ao_bits; - const int n_ai_chans; - const int n_ao_chans; - const struct comedi_lrange *ai_range_table, *ao_range_table; - int (*ai_rinsn) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*ao_rinsn) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); - int (*ao_winsn) (struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data); -}; - -static const struct comedi_lrange ranges_ai = { - 4, {RANGE(-5., 5.), RANGE(-10., 10.), RANGE(0., 5.), RANGE(0., 10.)} -}; - -static const struct comedi_lrange ranges_ao = { - 6, {RANGE(0., 5.), RANGE(0., 10.), RANGE(-5., 5.), RANGE(-10., 10.), - RANGE(-2.5, 2.5), RANGE(-2.5, 7.5)} -}; - -static const struct pcmmio_board pcmmio_boards[] = { - { - .name = "pcmmio", - .dio_num_asics = 1, - .dio_num_ports = 6, - .total_iosize = 32, - .ai_bits = 16, - .ao_bits = 16, - .n_ai_chans = 16, - .n_ao_chans = 8, - .ai_range_table = &ranges_ai, - .ao_range_table = &ranges_ao, - .ai_rinsn = ai_rinsn, - .ao_rinsn = ao_rinsn, - .ao_winsn = ao_winsn}, -}; /* - * Useful for shorthand access to the particular board structure + * Driver: pcmmio + * Description: A driver for the PCM-MIO multifunction board + * Devices: (Winsystems) PCM-MIO [pcmmio] + * Author: Calin Culianu <calin@ajvar.org> + * Updated: Wed, May 16 2007 16:21:10 -0500 + * Status: works + * + * A driver for the PCM-MIO multifunction board from Winsystems. This + * is a PC-104 based I/O board. It contains four subdevices: + * + * subdevice 0 - 16 channels of 16-bit AI + * subdevice 1 - 8 channels of 16-bit AO + * subdevice 2 - first 24 channels of the 48 channel of DIO + * (with edge-triggered interrupt support) + * subdevice 3 - last 24 channels of the 48 channel DIO + * (no interrupt support for this bank of channels) + * + * Some notes: + * + * Synchronous reads and writes are the only things implemented for analog + * input and output. The hardware itself can do streaming acquisition, etc. + * + * Asynchronous I/O for the DIO subdevices *is* implemented, however! They + * are basically edge-triggered interrupts for any configuration of the + * channels in subdevice 2. + * + * Also note that this interrupt support is untested. + * + * A few words about edge-detection IRQ support (commands on DIO): + * + * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ + * of the board to the comedi_config command. The board IRQ is not jumpered + * but rather configured through software, so any IRQ from 1-15 is OK. + * + * Due to the genericity of the comedi API, you need to create a special + * comedi_command in order to use edge-triggered interrupts for DIO. + * + * Use comedi_commands with TRIG_NOW. Your callback will be called each + * time an edge is detected on the specified DIO line(s), and the data + * values will be two sample_t's, which should be concatenated to form + * one 32-bit unsigned int. This value is the mask of channels that had + * edges detected from your channel list. Note that the bits positions + * in the mask correspond to positions in your chanlist when you + * specified the command and *not* channel id's! + * + * To set the polarity of the edge-detection interrupts pass a nonzero value + * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero + * value for both CR_RANGE and CR_AREF if you want edge-down polarity. + * + * Configuration Options: + * [0] - I/O port base address + * [1] - IRQ (optional -- for edge-detect interrupt support only, + * leave out if you don't need this feature) */ -#define thisboard ((const struct pcmmio_board *)dev->board_ptr) - -/* this structure is for data unique to this subdevice. */ -struct pcmmio_subdev_private { - - union { - /* for DIO: mapping of halfwords (bytes) - in port/chanarray to iobase */ - unsigned long iobases[PORTS_PER_SUBDEV]; - - /* for AI/AO */ - unsigned long iobase; - }; - union { - struct { - - /* The below is only used for intr subdevices */ - struct { - /* - * if non-negative, this subdev has an - * interrupt asic - */ - int asic; - /* - * if nonnegative, the first channel id for - * interrupts. - */ - int first_chan; - /* - * the number of asic channels in this subdev - * that have interrutps - */ - int num_asic_chans; - /* - * if nonnegative, the first channel id with - * respect to the asic that has interrupts - */ - int asic_chan; - /* - * subdev-relative channel mask for channels - * we are interested in - */ - int enabled_mask; - int active; - int stop_count; - int continuous; - spinlock_t spinlock; - } intr; - } dio; - struct { - /* the last unsigned int data written */ - unsigned int shadow_samples[8]; - } ao; - }; -}; -/* - * this structure is for data unique to this hardware driver. If - * several hardware drivers keep similar information in this structure, - * feel free to suggest moving the variable to the struct comedi_device struct. - */ -struct pcmmio_private { - /* stuff for DIO */ - struct { - unsigned char pagelock; /* current page and lock */ - /* shadow of POLx registers */ - unsigned char pol[NUM_PAGED_REGS]; - /* shadow of ENABx registers */ - unsigned char enab[NUM_PAGED_REGS]; - int num; - unsigned long iobase; - unsigned int irq; - spinlock_t spinlock; - } asics[MAX_ASICS]; - struct pcmmio_subdev_private *sprivs; -}; - -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct pcmmio_private *)dev->private) -#define subpriv ((struct pcmmio_subdev_private *)s->private) -/* - * 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 int pcmmio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcmmio_detach(struct comedi_device *dev); - -static struct comedi_driver driver = { - .driver_name = "pcmmio", - .module = THIS_MODULE, - .attach = pcmmio_attach, - .detach = pcmmio_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 pcmmio_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 = &pcmmio_boards[0].name, - .offset = sizeof(struct pcmmio_board), - .num_names = ARRAY_SIZE(pcmmio_boards), -}; - -static int pcmmio_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pcmmio_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static irqreturn_t interrupt_pcmmio(int irq, void *d); -static void pcmmio_stop_intr(struct comedi_device *, struct comedi_subdevice *); -static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -/* some helper functions to deal with specifics of this device's registers */ -/* sets up/clears ASIC chips to defaults */ -static void init_asics(struct comedi_device *dev); -static void switch_page(struct comedi_device *dev, int asic, int page); -#ifdef notused -static void lock_port(struct comedi_device *dev, int asic, int port); -static void unlock_port(struct comedi_device *dev, int asic, int port); -#endif - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - int sdev_no, chans_left, n_dio_subdevs, n_subdevs, port, asic, - thisasic_chanct = 0; - unsigned long iobase; - unsigned int irq[MAX_ASICS]; - - iobase = it->options[0]; - irq[0] = it->options[1]; - - printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name, - iobase); +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/slab.h> - dev->iobase = iobase; +#include "../comedidev.h" - if (!iobase || !request_region(iobase, - thisboard->total_iosize, - driver.driver_name)) { - printk("I/O port conflict\n"); - return -EIO; - } +#include "comedi_fc.h" /* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. + * Register I/O map */ - dev->board_name = thisboard->name; +#define PCMMIO_AI_LSB_REG 0x00 +#define PCMMIO_AI_MSB_REG 0x01 +#define PCMMIO_AI_CMD_REG 0x02 +#define PCMMIO_AI_CMD_SE (1 << 7) +#define PCMMIO_AI_CMD_ODD_CHAN (1 << 6) +#define PCMMIO_AI_CMD_CHAN_SEL(x) (((x) & 0x3) << 4) +#define PCMMIO_AI_CMD_RANGE(x) (((x) & 0x3) << 2) +#define PCMMIO_RESOURCE_REG 0x02 +#define PCMMIO_RESOURCE_IRQ(x) (((x) & 0xf) << 0) +#define PCMMIO_AI_STATUS_REG 0x03 +#define PCMMIO_AI_STATUS_DATA_READY (1 << 7) +#define PCMMIO_AI_STATUS_DATA_DMA_PEND (1 << 6) +#define PCMMIO_AI_STATUS_CMD_DMA_PEND (1 << 5) +#define PCMMIO_AI_STATUS_IRQ_PEND (1 << 4) +#define PCMMIO_AI_STATUS_DATA_DRQ_ENA (1 << 2) +#define PCMMIO_AI_STATUS_REG_SEL (1 << 3) +#define PCMMIO_AI_STATUS_CMD_DRQ_ENA (1 << 1) +#define PCMMIO_AI_STATUS_IRQ_ENA (1 << 0) +#define PCMMIO_AI_RES_ENA_REG 0x03 +#define PCMMIO_AI_RES_ENA_CMD_REG_ACCESS (0 << 3) +#define PCMMIO_AI_RES_ENA_AI_RES_ACCESS (1 << 3) +#define PCMMIO_AI_RES_ENA_DIO_RES_ACCESS (1 << 4) +#define PCMMIO_AI_2ND_ADC_OFFSET 0x04 + +#define PCMMIO_AO_LSB_REG 0x08 +#define PCMMIO_AO_LSB_SPAN(x) (((x) & 0xf) << 0) +#define PCMMIO_AO_MSB_REG 0x09 +#define PCMMIO_AO_CMD_REG 0x0a +#define PCMMIO_AO_CMD_WR_SPAN (0x2 << 4) +#define PCMMIO_AO_CMD_WR_CODE (0x3 << 4) +#define PCMMIO_AO_CMD_UPDATE (0x4 << 4) +#define PCMMIO_AO_CMD_UPDATE_ALL (0x5 << 4) +#define PCMMIO_AO_CMD_WR_SPAN_UPDATE (0x6 << 4) +#define PCMMIO_AO_CMD_WR_CODE_UPDATE (0x7 << 4) +#define PCMMIO_AO_CMD_WR_SPAN_UPDATE_ALL (0x8 << 4) +#define PCMMIO_AO_CMD_WR_CODE_UPDATE_ALL (0x9 << 4) +#define PCMMIO_AO_CMD_RD_B1_SPAN (0xa << 4) +#define PCMMIO_AO_CMD_RD_B1_CODE (0xb << 4) +#define PCMMIO_AO_CMD_RD_B2_SPAN (0xc << 4) +#define PCMMIO_AO_CMD_RD_B2_CODE (0xd << 4) +#define PCMMIO_AO_CMD_NOP (0xf << 4) +#define PCMMIO_AO_CMD_CHAN_SEL(x) (((x) & 0x03) << 1) +#define PCMMIO_AO_CMD_CHAN_SEL_ALL (0x0f << 0) +#define PCMMIO_AO_STATUS_REG 0x0b +#define PCMMIO_AO_STATUS_DATA_READY (1 << 7) +#define PCMMIO_AO_STATUS_DATA_DMA_PEND (1 << 6) +#define PCMMIO_AO_STATUS_CMD_DMA_PEND (1 << 5) +#define PCMMIO_AO_STATUS_IRQ_PEND (1 << 4) +#define PCMMIO_AO_STATUS_DATA_DRQ_ENA (1 << 2) +#define PCMMIO_AO_STATUS_REG_SEL (1 << 3) +#define PCMMIO_AO_STATUS_CMD_DRQ_ENA (1 << 1) +#define PCMMIO_AO_STATUS_IRQ_ENA (1 << 0) +#define PCMMIO_AO_RESOURCE_ENA_REG 0x0b +#define PCMMIO_AO_2ND_DAC_OFFSET 0x04 /* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. + * WinSystems WS16C48 + * + * Offset Page 0 Page 1 Page 2 Page 3 + * ------ ----------- ----------- ----------- ----------- + * 0x10 Port 0 I/O Port 0 I/O Port 0 I/O Port 0 I/O + * 0x11 Port 1 I/O Port 1 I/O Port 1 I/O Port 1 I/O + * 0x12 Port 2 I/O Port 2 I/O Port 2 I/O Port 2 I/O + * 0x13 Port 3 I/O Port 3 I/O Port 3 I/O Port 3 I/O + * 0x14 Port 4 I/O Port 4 I/O Port 4 I/O Port 4 I/O + * 0x15 Port 5 I/O Port 5 I/O Port 5 I/O Port 5 I/O + * 0x16 INT_PENDING INT_PENDING INT_PENDING INT_PENDING + * 0x17 Page/Lock Page/Lock Page/Lock Page/Lock + * 0x18 N/A POL_0 ENAB_0 INT_ID0 + * 0x19 N/A POL_1 ENAB_1 INT_ID1 + * 0x1a N/A POL_2 ENAB_2 INT_ID2 */ - if (alloc_private(dev, sizeof(struct pcmmio_private)) < 0) { - printk("cannot allocate private data structure\n"); - return -ENOMEM; - } - - for (asic = 0; asic < MAX_ASICS; ++asic) { - devpriv->asics[asic].num = asic; - devpriv->asics[asic].iobase = - dev->iobase + 16 + asic * ASIC_IOSIZE; - /* - * this gets actually set at the end of this function when we - * request_irqs - */ - devpriv->asics[asic].irq = 0; - spin_lock_init(&devpriv->asics[asic].spinlock); +#define PCMMIO_PORT_REG(x) (0x10 + (x)) +#define PCMMIO_INT_PENDING_REG 0x16 +#define PCMMIO_PAGE_LOCK_REG 0x17 +#define PCMMIO_LOCK_PORT(x) ((1 << (x)) & 0x3f) +#define PCMMIO_PAGE(x) (((x) & 0x3) << 6) +#define PCMMIO_PAGE_MASK PCMUIO_PAGE(3) +#define PCMMIO_PAGE_POL 1 +#define PCMMIO_PAGE_ENAB 2 +#define PCMMIO_PAGE_INT_ID 3 +#define PCMMIO_PAGE_REG(x) (0x18 + (x)) + +static const struct comedi_lrange pcmmio_ai_ranges = { + 4, { + BIP_RANGE(5), + BIP_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(10) } +}; - chans_left = CHANS_PER_ASIC * thisboard->dio_num_asics; - n_dio_subdevs = CALC_N_DIO_SUBDEVS(chans_left); - n_subdevs = n_dio_subdevs + 2; - devpriv->sprivs = - kcalloc(n_subdevs, sizeof(struct pcmmio_subdev_private), - GFP_KERNEL); - if (!devpriv->sprivs) { - printk("cannot allocate subdevice private data structures\n"); - return -ENOMEM; +static const struct comedi_lrange pcmmio_ao_ranges = { + 6, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10), + BIP_RANGE(2.5), + RANGE(-2.5, 7.5) } - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - * - * Allocate 1 AI + 1 AO + 2 DIO subdevs (24 lines per DIO) - */ - if (alloc_subdevices(dev, n_subdevs) < 0) { - printk("cannot allocate subdevice data structures\n"); - return -ENOMEM; - } - - /* First, AI */ - sdev_no = 0; - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = thisboard->ai_range_table; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->type = COMEDI_SUBD_AI; - s->n_chan = thisboard->n_ai_chans; - s->len_chanlist = s->n_chan; - s->insn_read = thisboard->ai_rinsn; - subpriv->iobase = dev->iobase + 0; - /* initialize the resource enable register by clearing it */ - outb(0, subpriv->iobase + 3); - outb(0, subpriv->iobase + 4 + 3); - - /* Next, AO */ - ++sdev_no; - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; - s->maxdata = (1 << thisboard->ao_bits) - 1; - s->range_table = thisboard->ao_range_table; - s->subdev_flags = SDF_READABLE; - s->type = COMEDI_SUBD_AO; - s->n_chan = thisboard->n_ao_chans; - s->len_chanlist = s->n_chan; - s->insn_read = thisboard->ao_rinsn; - s->insn_write = thisboard->ao_winsn; - subpriv->iobase = dev->iobase + 8; - /* initialize the resource enable register by clearing it */ - outb(0, subpriv->iobase + 3); - outb(0, subpriv->iobase + 4 + 3); - - ++sdev_no; - port = 0; - asic = 0; - for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) { - int byte_no; - - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; - s->maxdata = 1; - s->range_table = &range_digital; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->type = COMEDI_SUBD_DIO; - s->insn_bits = pcmmio_dio_insn_bits; - s->insn_config = pcmmio_dio_insn_config; - s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); - subpriv->dio.intr.asic = -1; - subpriv->dio.intr.first_chan = -1; - subpriv->dio.intr.asic_chan = -1; - subpriv->dio.intr.num_asic_chans = -1; - subpriv->dio.intr.active = 0; - s->len_chanlist = 1; - - /* save the ioport address for each 'port' of 8 channels in the - subdevice */ - for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { - if (port >= PORTS_PER_ASIC) { - port = 0; - ++asic; - thisasic_chanct = 0; - } - subpriv->iobases[byte_no] = - devpriv->asics[asic].iobase + port; - - if (thisasic_chanct < - CHANS_PER_PORT * INTR_PORTS_PER_ASIC - && subpriv->dio.intr.asic < 0) { - /* - * this is an interrupt subdevice, - * so setup the struct - */ - subpriv->dio.intr.asic = asic; - subpriv->dio.intr.active = 0; - subpriv->dio.intr.stop_count = 0; - subpriv->dio.intr.first_chan = byte_no * 8; - subpriv->dio.intr.asic_chan = thisasic_chanct; - subpriv->dio.intr.num_asic_chans = - s->n_chan - subpriv->dio.intr.first_chan; - s->cancel = pcmmio_cancel; - s->do_cmd = pcmmio_cmd; - s->do_cmdtest = pcmmio_cmdtest; - s->len_chanlist = - subpriv->dio.intr.num_asic_chans; - } - thisasic_chanct += CHANS_PER_PORT; - } - spin_lock_init(&subpriv->dio.intr.spinlock); - - chans_left -= s->n_chan; - - if (!chans_left) { - /* - * reset the asic to our first asic, - * to do intr subdevs - */ - asic = 0; - port = 0; - } +}; - } +struct pcmmio_private { + spinlock_t pagelock; /* protects the page registers */ + spinlock_t spinlock; /* protects the member variables */ + unsigned int enabled_mask; + unsigned int stop_count; + unsigned int active:1; - init_asics(dev); /* clear out all the registers, basically */ - - for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { - if (irq[asic] - && request_irq(irq[asic], interrupt_pcmmio, - IRQF_SHARED, thisboard->name, dev)) { - int i; - /* unroll the allocated irqs.. */ - for (i = asic - 1; i >= 0; --i) { - free_irq(irq[i], dev); - devpriv->asics[i].irq = irq[i] = 0; - } - irq[asic] = 0; - } - devpriv->asics[asic].irq = irq[asic]; - } + unsigned int ao_readback[8]; +}; - dev->irq = irq[0]; /* - * grr.. wish comedi dev struct supported - * multiple irqs.. - */ +static void pcmmio_dio_write(struct comedi_device *dev, unsigned int val, + int page, int port) +{ + struct pcmmio_private *devpriv = dev->private; + unsigned long iobase = dev->iobase; + unsigned long flags; - if (irq[0]) { - printk("irq: %u ", irq[0]); - if (thisboard->dio_num_asics == 2 && irq[1]) - printk("second ASIC irq: %u ", irq[1]); + spin_lock_irqsave(&devpriv->pagelock, flags); + if (page == 0) { + /* Port registers are valid for any page */ + outb(val & 0xff, iobase + PCMMIO_PORT_REG(port + 0)); + outb((val >> 8) & 0xff, iobase + PCMMIO_PORT_REG(port + 1)); + outb((val >> 16) & 0xff, iobase + PCMMIO_PORT_REG(port + 2)); } else { - printk("(IRQ mode disabled) "); + outb(PCMMIO_PAGE(page), iobase + PCMMIO_PAGE_LOCK_REG); + outb(val & 0xff, iobase + PCMMIO_PAGE_REG(0)); + outb((val >> 8) & 0xff, iobase + PCMMIO_PAGE_REG(1)); + outb((val >> 16) & 0xff, iobase + PCMMIO_PAGE_REG(2)); } - - printk("attached\n"); - - return 1; + spin_unlock_irqrestore(&devpriv->pagelock, flags); } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pcmmio_detach(struct comedi_device *dev) +static unsigned int pcmmio_dio_read(struct comedi_device *dev, + int page, int port) { - int i; - - printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name); - if (dev->iobase) - release_region(dev->iobase, thisboard->total_iosize); - - for (i = 0; i < MAX_ASICS; ++i) { - if (devpriv && devpriv->asics[i].irq) - free_irq(devpriv->asics[i].irq, dev); + struct pcmmio_private *devpriv = dev->private; + unsigned long iobase = dev->iobase; + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&devpriv->pagelock, flags); + if (page == 0) { + /* Port registers are valid for any page */ + val = inb(iobase + PCMMIO_PORT_REG(port + 0)); + val |= (inb(iobase + PCMMIO_PORT_REG(port + 1)) << 8); + val |= (inb(iobase + PCMMIO_PORT_REG(port + 2)) << 16); + } else { + outb(PCMMIO_PAGE(page), iobase + PCMMIO_PAGE_LOCK_REG); + val = inb(iobase + PCMMIO_PAGE_REG(0)); + val |= (inb(iobase + PCMMIO_PAGE_REG(1)) << 8); + val |= (inb(iobase + PCMMIO_PAGE_REG(2)) << 16); } + spin_unlock_irqrestore(&devpriv->pagelock, flags); - if (devpriv && devpriv->sprivs) - kfree(devpriv->sprivs); - - return 0; + return val; } -/* DIO devices are slightly special. Although it is possible to - * implement the insn_read/insn_write interface, it is much more - * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ +/* + * Each channel can be individually programmed for input or output. + * Writing a '0' to a channel causes the corresponding output pin + * to go to a high-z state (pulled high by an external 10K resistor). + * This allows it to be used as an input. When used in the input mode, + * a read reflects the inverted state of the I/O pin, such that a + * high on the pin will read as a '0' in the register. Writing a '1' + * to a bit position causes the pin to sink current (up to 12mA), + * effectively pulling it low. + */ static int pcmmio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int byte_no; - if (insn->n != 2) - return -EINVAL; - - /* NOTE: - reading a 0 means this channel was high - writine a 0 sets the channel high - reading a 1 means this channel was low - writing a 1 means set this channel low - - Therefore everything is always inverted. */ - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk("write mask: %08x data: %08x\n", data[0], data[1]); -#endif - - s->state = 0; - - for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { - /* address of 8-bit port */ - unsigned long ioaddr = subpriv->iobases[byte_no], - /* bit offset of port in 32-bit doubleword */ - offset = byte_no * 8; - /* this 8-bit port's data */ - unsigned char byte = 0, - /* The write mask for this port (if any) */ - write_mask_byte = (data[0] >> offset) & 0xff, - /* The data byte for this port */ - data_byte = (data[1] >> offset) & 0xff; - - byte = inb(ioaddr); /* read all 8-bits for this port */ - -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk - ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", - byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, - offset, ioaddr, (unsigned)byte); -#endif - - if (write_mask_byte) { - /* - * this byte has some write_bits - * -- so set the output lines - */ - /* clear bits for write mask */ - byte &= ~write_mask_byte; - /* set to inverted data_byte */ - byte |= ~data_byte & write_mask_byte; - /* Write out the new digital output state */ - outb(byte, ioaddr); - } -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk("data_out_byte %02x\n", (unsigned)byte); -#endif - /* save the digital input lines for this byte.. */ - s->state |= ((unsigned int)byte) << offset; + /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */ + int port = s->index == 2 ? 0 : 3; + unsigned int chanmask = (1 << s->n_chan) - 1; + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + /* + * Outputs are inverted, invert the state and + * update the channels. + * + * The s->io_bits mask makes sure the input channels + * are '0' so that the outputs pins stay in a high + * z-state. + */ + val = ~s->state & chanmask; + val &= s->io_bits; + pcmmio_dio_write(dev, val, 0, port); } - /* now return the DIO lines to data[1] - note they came inverted! */ - data[1] = ~s->state; + /* get inverted state of the channels from the port */ + val = pcmmio_dio_read(dev, 0, port); -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk("s->state %08x data_out %08x\n", s->state, data[1]); -#endif + /* return the true state of the channels */ + data[1] = ~val & chanmask; - return 2; + return insn->n; } -/* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ static int pcmmio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = - chan % 8; - unsigned long ioaddr; - unsigned char byte; + /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */ + int port = s->index == 2 ? 0 : 3; + int ret; - /* Compute ioaddr for this channel */ - ioaddr = subpriv->iobases[byte_no]; + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - /* NOTE: - writing a 0 an IO channel's bit sets the channel to INPUT - and pulls the line high as well + if (data[0] == INSN_CONFIG_DIO_INPUT) + pcmmio_dio_write(dev, s->io_bits, 0, port); - writing a 1 to an IO channel's bit pulls the line low + return insn->n; +} - All channels are implicitly always in OUTPUT mode -- but when - they are high they can be considered to be in INPUT mode.. +static void pcmmio_reset(struct comedi_device *dev) +{ + /* Clear all the DIO port bits */ + pcmmio_dio_write(dev, 0, 0, 0); + pcmmio_dio_write(dev, 0, 0, 3); + + /* Clear all the paged registers */ + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_POL, 0); + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_ENAB, 0); + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_INT_ID, 0); +} - Thus, we only force channels low if the config request was INPUT, - otherwise we do nothing to the hardware. */ +/* devpriv->spinlock is already locked */ +static void pcmmio_stop_intr(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcmmio_private *devpriv = dev->private; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - /* save to io_bits -- don't actually do anything since - all input channels are also output channels... */ - s->io_bits |= 1 << chan; - break; - case INSN_CONFIG_DIO_INPUT: - /* write a 0 to the actual register representing the channel - to set it to 'input'. 0 means "float high". */ - byte = inb(ioaddr); - byte &= ~(1 << bit_no); - /**< set input channel to '0' */ + devpriv->enabled_mask = 0; + devpriv->active = 0; + s->async->inttrig = NULL; - /* - * write out byte -- this is the only time we actually affect - * the hardware as all channels are implicitly output - * -- but input channels are set to float-high - */ - outb(byte, ioaddr); + /* disable all dio interrupts */ + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_ENAB, 0); +} - /* save to io_bits */ - s->io_bits &= ~(1 << chan); - break; +static void pcmmio_handle_dio_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int triggered) +{ + struct pcmmio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int oldevents = s->async->events; + unsigned int val = 0; + unsigned long flags; + int i; - case INSN_CONFIG_DIO_QUERY: - /* retrieve from shadow register */ - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; + spin_lock_irqsave(&devpriv->spinlock, flags); - default: - return -EINVAL; - break; - } + if (!devpriv->active) + goto done; - return insn->n; -} + if (!(triggered & devpriv->enabled_mask)) + goto done; -static void init_asics(struct comedi_device *dev) -{ /* sets up an - ASIC chip to defaults */ - int asic; - - for (asic = 0; asic < thisboard->dio_num_asics; ++asic) { - int port, page; - unsigned long baseaddr = devpriv->asics[asic].iobase; - - switch_page(dev, asic, 0); /* switch back to page 0 */ - - /* first, clear all the DIO port bits */ - for (port = 0; port < PORTS_PER_ASIC; ++port) - outb(0, baseaddr + REG_PORT0 + port); - - /* Next, clear all the paged registers for each page */ - for (page = 1; page < NUM_PAGES; ++page) { - int reg; - /* now clear all the paged registers */ - switch_page(dev, asic, page); - for (reg = FIRST_PAGED_REG; - reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg) - outb(0, baseaddr + reg); - } + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); - /* DEBUG set rising edge interrupts on port0 of both asics */ - /*switch_page(dev, asic, PAGE_POL); - outb(0xff, baseaddr + REG_POL0); - switch_page(dev, asic, PAGE_ENAB); - outb(0xff, baseaddr + REG_ENAB0); */ - /* END DEBUG */ + if (triggered & (1 << chan)) + val |= (1 << i); + } - /* switch back to default page 0 */ - switch_page(dev, asic, 0); + /* Write the scan to the buffer. */ + if (comedi_buf_put(s, val) && + comedi_buf_put(s, val >> 16)) { + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + } else { + /* Overflow! Stop acquisition!! */ + /* TODO: STOP_ACQUISITION_CALL_HERE!! */ + pcmmio_stop_intr(dev, s); } -} -static void switch_page(struct comedi_device *dev, int asic, int page) -{ - if (asic < 0 || asic >= thisboard->dio_num_asics) - return; /* paranoia */ - if (page < 0 || page >= NUM_PAGES) - return; /* more paranoia */ + /* Check for end of acquisition. */ + if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count > 0) { + devpriv->stop_count--; + if (devpriv->stop_count == 0) { + s->async->events |= COMEDI_CB_EOA; + /* TODO: STOP_ACQUISITION_CALL_HERE!! */ + pcmmio_stop_intr(dev, s); + } + } - devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; - devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; +done: + spin_unlock_irqrestore(&devpriv->spinlock, flags); - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - devpriv->asics[asic].iobase + REG_PAGELOCK); + if (oldevents != s->async->events) + comedi_event(dev, s); } -#ifdef notused -static void lock_port(struct comedi_device *dev, int asic, int port) +static irqreturn_t interrupt_pcmmio(int irq, void *d) { - if (asic < 0 || asic >= thisboard->dio_num_asics) - return; /* paranoia */ - if (port < 0 || port >= PORTS_PER_ASIC) - return; /* more paranoia */ - - devpriv->asics[asic].pagelock |= 0x1 << port; - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - devpriv->asics[asic].iobase + REG_PAGELOCK); - return; -} + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + unsigned int triggered; + unsigned char int_pend; -static void unlock_port(struct comedi_device *dev, int asic, int port) -{ - if (asic < 0 || asic >= thisboard->dio_num_asics) - return; /* paranoia */ - if (port < 0 || port >= PORTS_PER_ASIC) - return; /* more paranoia */ - devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK; - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - devpriv->asics[asic].iobase + REG_PAGELOCK); -} -#endif /* notused */ + /* are there any interrupts pending */ + int_pend = inb(dev->iobase + PCMMIO_INT_PENDING_REG) & 0x07; + if (!int_pend) + return IRQ_NONE; -static irqreturn_t interrupt_pcmmio(int irq, void *d) -{ - int asic, got1 = 0; - struct comedi_device *dev = (struct comedi_device *)d; - - for (asic = 0; asic < MAX_ASICS; ++asic) { - if (irq == devpriv->asics[asic].irq) { - unsigned long flags; - unsigned triggered = 0; - unsigned long iobase = devpriv->asics[asic].iobase; - /* it is an interrupt for ASIC #asic */ - unsigned char int_pend; - - spin_lock_irqsave(&devpriv->asics[asic].spinlock, - flags); - - int_pend = inb(iobase + REG_INT_PENDING) & 0x07; - - if (int_pend) { - int port; - for (port = 0; port < INTR_PORTS_PER_ASIC; - ++port) { - if (int_pend & (0x1 << port)) { - unsigned char - io_lines_with_edges = 0; - switch_page(dev, asic, - PAGE_INT_ID); - io_lines_with_edges = - inb(iobase + - REG_INT_ID0 + port); - - if (io_lines_with_edges) - /* - * clear pending - * interrupt - */ - outb(0, iobase + - REG_INT_ID0 + - port); - - triggered |= - io_lines_with_edges << - port * 8; - } - } - - ++got1; - } - - spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, - flags); - - if (triggered) { - struct comedi_subdevice *s; - /* - * TODO here: dispatch io lines to subdevs - * with commands.. - */ - printk - ("PCMMIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", - irq, asic, triggered); - for (s = dev->subdevices + 2; - s < dev->subdevices + dev->n_subdevices; - ++s) { - /* - * this is an interrupt subdev, - * and it matches this asic! - */ - if (subpriv->dio.intr.asic == asic) { - unsigned long flags; - unsigned oldevents; - - spin_lock_irqsave(&subpriv->dio. - intr.spinlock, - flags); - - oldevents = s->async->events; - - if (subpriv->dio.intr.active) { - unsigned mytrig = - ((triggered >> - subpriv->dio.intr.asic_chan) - & - ((0x1 << subpriv-> - dio.intr. - num_asic_chans) - - 1)) << subpriv-> - dio.intr.first_chan; - if (mytrig & - subpriv->dio. - intr.enabled_mask) { - unsigned int val - = 0; - unsigned int n, - ch, len; - - len = - s-> - async->cmd.chanlist_len; - for (n = 0; - n < len; - n++) { - ch = CR_CHAN(s->async->cmd.chanlist[n]); - if (mytrig & (1U << ch)) - val |= (1U << n); - } - /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *)&val)[0]) - && - comedi_buf_put - (s->async, - ((short *) - &val)[1])) { - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); - } else { - /* Overflow! Stop acquisition!! */ - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmmio_stop_intr - (dev, - s); - } - - /* Check for end of acquisition. */ - if (!subpriv->dio.intr.continuous) { - /* stop_src == TRIG_COUNT */ - if (subpriv->dio.intr.stop_count > 0) { - subpriv->dio.intr.stop_count--; - if (subpriv->dio.intr.stop_count == 0) { - s->async->events |= COMEDI_CB_EOA; - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmmio_stop_intr - (dev, - s); - } - } - } - } - } - - spin_unlock_irqrestore - (&subpriv->dio.intr. - spinlock, flags); - - if (oldevents != - s->async->events) { - comedi_event(dev, s); - } - - } - - } - } + /* get, and clear, the pending interrupts */ + triggered = pcmmio_dio_read(dev, PCMMIO_PAGE_INT_ID, 0); + pcmmio_dio_write(dev, 0, PCMMIO_PAGE_INT_ID, 0); - } - } - if (!got1) - return IRQ_NONE; /* interrupt from other source */ - return IRQ_HANDLED; -} + pcmmio_handle_dio_intr(dev, s, triggered); -static void pcmmio_stop_intr(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - int nports, firstport, asic, port; - - asic = subpriv->dio.intr.asic; - if (asic < 0) - return; /* not an interrupt subdev */ - - subpriv->dio.intr.enabled_mask = 0; - subpriv->dio.intr.active = 0; - s->async->inttrig = 0; - nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT; - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - /* disable all intrs for this subdev.. */ - outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); - } + return IRQ_HANDLED; } +/* devpriv->spinlock is already locked */ static int pcmmio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { - if (!subpriv->dio.intr.continuous && subpriv->dio.intr.stop_count == 0) { + struct pcmmio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int bits = 0; + unsigned int pol_bits = 0; + int i; + + if (cmd->stop_src == TRIG_COUNT && devpriv->stop_count == 0) { /* An empty acquisition! */ s->async->events |= COMEDI_CB_EOA; - subpriv->dio.intr.active = 0; + devpriv->active = 0; return 1; - } else { - unsigned bits = 0, pol_bits = 0, n; - int nports, firstport, asic, port; - struct comedi_cmd *cmd = &s->async->cmd; - - asic = subpriv->dio.intr.asic; - if (asic < 0) - return 1; /* not an interrupt - subdev */ - subpriv->dio.intr.enabled_mask = 0; - subpriv->dio.intr.active = 1; - nports = subpriv->dio.intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->dio.intr.asic_chan / CHANS_PER_PORT; - if (cmd->chanlist) { - for (n = 0; n < cmd->chanlist_len; n++) { - bits |= (1U << CR_CHAN(cmd->chanlist[n])); - pol_bits |= (CR_AREF(cmd->chanlist[n]) - || CR_RANGE(cmd-> - chanlist[n]) ? 1U : 0U) - << CR_CHAN(cmd->chanlist[n]); - } - } - bits &= ((0x1 << subpriv->dio.intr.num_asic_chans) - - 1) << subpriv->dio.intr.first_chan; - subpriv->dio.intr.enabled_mask = bits; - - { - /* - * the below code configures the board - * to use a specific IRQ from 0-15. - */ - unsigned char b; - /* - * set resource enable register - * to enable IRQ operation - */ - outb(1 << 4, dev->iobase + 3); - /* set bits 0-3 of b to the irq number from 0-15 */ - b = dev->irq & ((1 << 4) - 1); - outb(b, dev->iobase + 2); - /* done, we told the board what irq to use */ - } + } - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - unsigned enab = - bits >> (subpriv->dio.intr.first_chan + (port - - firstport) - * 8) & 0xff, pol = - pol_bits >> (subpriv->dio.intr.first_chan + - (port - firstport) * 8) & 0xff; - /* set enab intrs for this subdev.. */ - outb(enab, - devpriv->asics[asic].iobase + REG_ENAB0 + port); - switch_page(dev, asic, PAGE_POL); - outb(pol, - devpriv->asics[asic].iobase + REG_ENAB0 + port); + devpriv->enabled_mask = 0; + devpriv->active = 1; + if (cmd->chanlist) { + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chanspec = cmd->chanlist[i]; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + + bits |= (1 << chan); + pol_bits |= (((aref || range) ? 1 : 0) << chan); } } + bits &= ((1 << s->n_chan) - 1); + devpriv->enabled_mask = bits; + + /* set polarity and enable interrupts */ + pcmmio_dio_write(dev, pol_bits, PCMMIO_PAGE_POL, 0); + pcmmio_dio_write(dev, bits, PCMMIO_PAGE_ENAB, 0); + return 0; } static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcmmio_private *devpriv = dev->private; unsigned long flags; - spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); - if (subpriv->dio.intr.active) + spin_lock_irqsave(&devpriv->spinlock, flags); + if (devpriv->active) pcmmio_stop_intr(dev, s); - spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + spin_unlock_irqrestore(&devpriv->spinlock, flags); return 0; } -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pcmmio_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { + struct pcmmio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; - spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); - s->async->inttrig = 0; - if (subpriv->dio.intr.active) + spin_lock_irqsave(&devpriv->spinlock, flags); + s->async->inttrig = NULL; + if (devpriv->active) event = pcmmio_start_intr(dev, s); - spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + spin_unlock_irqrestore(&devpriv->spinlock, flags); if (event) comedi_event(dev, s); @@ -1120,37 +489,27 @@ pcmmio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, */ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcmmio_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned long flags; int event = 0; - spin_lock_irqsave(&subpriv->dio.intr.spinlock, flags); - subpriv->dio.intr.active = 1; + spin_lock_irqsave(&devpriv->spinlock, flags); + devpriv->active = 1; /* Set up end of acquisition. */ - switch (cmd->stop_src) { - case TRIG_COUNT: - subpriv->dio.intr.continuous = 0; - subpriv->dio.intr.stop_count = cmd->stop_arg; - break; - default: - /* TRIG_NONE */ - subpriv->dio.intr.continuous = 1; - subpriv->dio.intr.stop_count = 0; - break; - } + if (cmd->stop_src == TRIG_COUNT) + devpriv->stop_count = cmd->stop_arg; + else /* TRIG_NONE */ + devpriv->stop_count = 0; /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: + if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmmio_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = pcmmio_start_intr(dev, s); - break; - } - spin_unlock_irqrestore(&subpriv->dio.intr.spinlock, flags); + + spin_unlock_irqrestore(&devpriv->spinlock, flags); if (event) comedi_event(dev, s); @@ -1158,201 +517,333 @@ static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -static int -pcmmio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int pcmmio_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - return comedi_pcm_cmdtest(dev, s, cmd); + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_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); + 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); + + switch (cmd->stop_src) { + case TRIG_COUNT: + /* any count allowed */ + break; + case TRIG_NONE: + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + break; + default: + break; + } + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + /* if (err) return 4; */ + + return 0; } -static int adc_wait_ready(unsigned long iobase) +static int pcmmio_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned long retry = 100000; - while (retry--) - if (inb(iobase + 3) & 0x80) - return 0; - return 1; + unsigned char status; + + status = inb(dev->iobase + PCMMIO_AI_STATUS_REG); + if (status & PCMMIO_AI_STATUS_DATA_READY) + return 0; + return -EBUSY; } -/* All this is for AI and AO */ -static int ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcmmio_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - unsigned long iobase = subpriv->iobase; + unsigned long iobase = dev->iobase; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int aref = CR_AREF(insn->chanspec); + unsigned char cmd = 0; + unsigned int val; + int ret; + int i; /* - 1. write the CMD byte (to BASE+2) - 2. read junk lo byte (BASE+0) - 3. read junk hi byte (BASE+1) - 4. (mux settled so) write CMD byte again (BASE+2) - 5. read valid lo byte(BASE+0) - 6. read valid hi byte(BASE+1) - - Additionally note that the BASE += 4 if the channel >= 8 + * The PCM-MIO uses two Linear Tech LTC1859CG 8-channel A/D converters. + * The devices use a full duplex serial interface which transmits and + * receives data simultaneously. An 8-bit command is shifted into the + * ADC interface to configure it for the next conversion. At the same + * time, the data from the previous conversion is shifted out of the + * device. Consequently, the conversion result is delayed by one + * conversion from the command word. + * + * Setup the cmd for the conversions then do a dummy conversion to + * flush the junk data. Then do each conversion requested by the + * comedi_insn. Note that the last conversion will leave junk data + * in ADC which will get flushed on the next comedi_insn. */ - /* convert n samples */ - for (n = 0; n < insn->n; n++) { - unsigned chan = CR_CHAN(insn->chanspec), range = - CR_RANGE(insn->chanspec), aref = CR_AREF(insn->chanspec); - unsigned char command_byte = 0; - unsigned iooffset = 0; - short sample, adc_adjust = 0; - - if (chan > 7) - chan -= 8, iooffset = 4; /* - * use the second dword - * for channels > 7 - */ - - if (aref != AREF_DIFF) { - aref = AREF_GROUND; - command_byte |= 1 << 7; /* - * set bit 7 to indicate - * single-ended - */ - } - if (range < 2) - adc_adjust = 0x8000; /* - * bipolar ranges - * (-5,5 .. -10,10 need to be - * adjusted -- that is.. they - * need to wrap around by - * adding 0x8000 - */ - - if (chan % 2) { - command_byte |= 1 << 6; /* - * odd-numbered channels - * have bit 6 set - */ - } + if (chan > 7) { + chan -= 8; + iobase += PCMMIO_AI_2ND_ADC_OFFSET; + } - /* select the channel, bits 4-5 == chan/2 */ - command_byte |= ((chan / 2) & 0x3) << 4; + if (aref == AREF_GROUND) + cmd |= PCMMIO_AI_CMD_SE; + if (chan % 2) + cmd |= PCMMIO_AI_CMD_ODD_CHAN; + cmd |= PCMMIO_AI_CMD_CHAN_SEL(chan / 2); + cmd |= PCMMIO_AI_CMD_RANGE(range); - /* set the range, bits 2-3 */ - command_byte |= (range & 0x3) << 2; + outb(cmd, iobase + PCMMIO_AI_CMD_REG); - /* need to do this twice to make sure mux settled */ - /* chan/range/aref select */ - outb(command_byte, iobase + iooffset + 2); + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); + if (ret) + return ret; - /* wait for the adc to say it finised the conversion */ - adc_wait_ready(iobase + iooffset); + val = inb(iobase + PCMMIO_AI_LSB_REG); + val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8; - /* select the chan/range/aref AGAIN */ - outb(command_byte, iobase + iooffset + 2); + for (i = 0; i < insn->n; i++) { + outb(cmd, iobase + PCMMIO_AI_CMD_REG); - adc_wait_ready(iobase + iooffset); + ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0); + if (ret) + return ret; - /* read data lo byte */ - sample = inb(iobase + iooffset + 0); + val = inb(iobase + PCMMIO_AI_LSB_REG); + val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8; - /* read data hi byte */ - sample |= inb(iobase + iooffset + 1) << 8; - sample += adc_adjust; /* adjustment .. munge data */ - data[n] = sample; + /* bipolar data is two's complement */ + if (comedi_range_is_bipolar(s, range)) + val = comedi_offset_munge(s, val); + + data[i] = val; } - /* return the number of samples read/written */ - return n; + + return insn->n; } -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcmmio_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int n; - for (n = 0; n < insn->n; n++) { - unsigned chan = CR_CHAN(insn->chanspec); - if (chan < s->n_chan) - data[n] = subpriv->ao.shadow_samples[chan]; - } - return n; + struct pcmmio_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + + return insn->n; } -static int wait_dac_ready(unsigned long iobase) +static int pcmmio_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - unsigned long retry = 100000L; + unsigned char status; - /* This may seem like an absurd way to handle waiting and violates the - "no busy waiting" policy. The fact is that the hardware is - normally so fast that we usually only need one time through the loop - anyway. The longer timeout is for rare occasions and for detecting - non-existent hardware. */ + status = inb(dev->iobase + PCMMIO_AO_STATUS_REG); + if (status & PCMMIO_AO_STATUS_DATA_READY) + return 0; + return -EBUSY; +} - while (retry--) { - if (inb(iobase + 3) & 0x80) - return 0; +static int pcmmio_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct pcmmio_private *devpriv = dev->private; + unsigned long iobase = dev->iobase; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val = devpriv->ao_readback[chan]; + unsigned char cmd = 0; + int ret; + int i; + /* + * The PCM-MIO has two Linear Tech LTC2704 DAC devices. Each device + * is a 4-channel converter with software-selectable output range. + */ + + if (chan > 3) { + cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan - 4); + iobase += PCMMIO_AO_2ND_DAC_OFFSET; + } else { + cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan); } - return 1; + + /* set the range for the channel */ + outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG); + outb(0, iobase + PCMMIO_AO_MSB_REG); + outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); + if (ret) + return ret; + + for (i = 0; i < insn->n; i++) { + val = data[i]; + + /* write the data to the channel */ + outb(val & 0xff, iobase + PCMMIO_AO_LSB_REG); + outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG); + outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE, + iobase + PCMMIO_AO_CMD_REG); + + ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0); + if (ret) + return ret; + + devpriv->ao_readback[chan] = val; + } + + return insn->n; } -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - int n; - unsigned iobase = subpriv->iobase, iooffset = 0; - - for (n = 0; n < insn->n; n++) { - unsigned chan = CR_CHAN(insn->chanspec), range = - CR_RANGE(insn->chanspec); - if (chan < s->n_chan) { - unsigned char command_byte = 0, range_byte = - range & ((1 << 4) - 1); - if (chan >= 4) - chan -= 4, iooffset += 4; - /* set the range.. */ - outb(range_byte, iobase + iooffset + 0); - outb(0, iobase + iooffset + 1); - - /* tell it to begin */ - command_byte = (chan << 1) | 0x60; - outb(command_byte, iobase + iooffset + 2); - - wait_dac_ready(iobase + iooffset); - - /* low order byte */ - outb(data[n] & 0xff, iobase + iooffset + 0); - - /* high order byte */ - outb((data[n] >> 8) & 0xff, iobase + iooffset + 1); - - /* - * set bit 4 of command byte to indicate - * data is loaded and trigger conversion - */ - command_byte = 0x70 | (chan << 1); - /* trigger converion */ - outb(command_byte, iobase + iooffset + 2); - - wait_dac_ready(iobase + iooffset); - - /* save to shadow register for ao_rinsn */ - subpriv->ao.shadow_samples[chan] = data[n]; + struct pcmmio_private *devpriv; + struct comedi_subdevice *s; + int ret; + + ret = comedi_request_region(dev, it->options[0], 32); + if (ret) + return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + spin_lock_init(&devpriv->pagelock); + spin_lock_init(&devpriv->spinlock); + + pcmmio_reset(dev); + + if (it->options[1]) { + ret = request_irq(it->options[1], interrupt_pcmmio, 0, + dev->board_name, dev); + if (ret == 0) { + dev->irq = it->options[1]; + + /* configure the interrupt routing on the board */ + outb(PCMMIO_AI_RES_ENA_DIO_RES_ACCESS, + dev->iobase + PCMMIO_AI_RES_ENA_REG); + outb(PCMMIO_RESOURCE_IRQ(dev->irq), + dev->iobase + PCMMIO_RESOURCE_REG); } } - return n; -} -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_init_module(void) -{ - return comedi_driver_register(&driver); -} + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; -static void __exit driver_cleanup_module(void) -{ - comedi_driver_unregister(&driver); + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = 0xffff; + s->range_table = &pcmmio_ai_ranges; + s->insn_read = pcmmio_ai_insn_read; + + /* initialize the resource enable register by clearing it */ + outb(PCMMIO_AI_RES_ENA_CMD_REG_ACCESS, + dev->iobase + PCMMIO_AI_RES_ENA_REG); + outb(PCMMIO_AI_RES_ENA_CMD_REG_ACCESS, + dev->iobase + PCMMIO_AI_RES_ENA_REG + PCMMIO_AI_2ND_ADC_OFFSET); + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->maxdata = 0xffff; + s->range_table = &pcmmio_ao_ranges; + s->insn_read = pcmmio_ao_insn_read; + s->insn_write = pcmmio_ao_insn_write; + + /* initialize the resource enable register by clearing it */ + outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG); + outb(0, dev->iobase + PCMMIO_AO_2ND_DAC_OFFSET + + PCMMIO_AO_RESOURCE_ENA_REG); + + /* Digital I/O subdevice with interrupt support */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->len_chanlist = 1; + s->range_table = &range_digital; + s->insn_bits = pcmmio_dio_insn_bits; + s->insn_config = pcmmio_dio_insn_config; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->cancel = pcmmio_cancel; + s->do_cmd = pcmmio_cmd; + s->do_cmdtest = pcmmio_cmdtest; + } + + /* Digital I/O subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcmmio_dio_insn_bits; + s->insn_config = pcmmio_dio_insn_config; + + return 0; } -module_init(driver_init_module); -module_exit(driver_cleanup_module); +static struct comedi_driver pcmmio_driver = { + .driver_name = "pcmmio", + .module = THIS_MODULE, + .attach = pcmmio_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(pcmmio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Winsystems PCM-MIO PC/104 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index b2c2c8971a3..62914bb342d 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -1,964 +1,488 @@ /* - comedi/drivers/pcmuio.c - Driver for Winsystems PC-104 based 48-channel and 96-channel DIO boards. - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * pcmuio.c + * Comedi driver for Winsystems PC-104 based 48/96-channel DIO boards. + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2006 Calin A. Culianu <calin@ajvar.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + /* -Driver: pcmuio -Description: A driver for the PCM-UIO48A and PCM-UIO96A boards from Winsystems. -Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96) -Author: Calin Culianu <calin@ajvar.org> -Updated: Fri, 13 Jan 2006 12:01:01 -0500 -Status: works - -A driver for the relatively straightforward-to-program PCM-UIO48A and -PCM-UIO96A boards from Winsystems. These boards use either one or two -(in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO). -This chip is interesting in that each I/O line is individually -programmable for INPUT or OUTPUT (thus comedi_dio_config can be done -on a per-channel basis). Also, each chip supports edge-triggered -interrupts for the first 24 I/O lines. Of course, since the -96-channel version of the board has two ASICs, it can detect polarity -changes on up to 48 I/O lines. Since this is essentially an (non-PnP) -ISA board, I/O Address and IRQ selection are done through jumpers on -the board. You need to pass that information to this driver as the -first and second comedi_config option, respectively. Note that the -48-channel version uses 16 bytes of IO memory and the 96-channel -version uses 32-bytes (in case you are worried about conflicts). The -48-channel board is split into two 24-channel comedi subdevices. -The 96-channel board is split into 4 24-channel DIO subdevices. - -Note that IRQ support has been added, but it is untested. - -To use edge-detection IRQ support, pass the IRQs of both ASICS -(for the 96 channel version) or just 1 ASIC (for 48-channel version). -Then, use use comedi_commands with TRIG_NOW. -Your callback will be called each time an edge is triggered, and the data -values will be two sample_t's, which should be concatenated to form one -32-bit unsigned int. This value is the mask of channels that had -edges detected from your channel list. Note that the bits positions -in the mask correspond to positions in your chanlist when you specified -the command and *not* channel id's! - -To set the polarity of the edge-detection interrupts pass a nonzero value for -either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for both -CR_RANGE and CR_AREF if you want edge-down polarity. - -In the 48-channel version: - -On subdev 0, the first 24 channels channels are edge-detect channels. - -In the 96-channel board you have the collowing channels that can do edge detection: - -subdev 0, channels 0-24 (first 24 channels of 1st ASIC) -subdev 2, channels 0-24 (first 24 channels of 2nd ASIC) - -Configuration Options: - [0] - I/O port base address - [1] - IRQ (for first ASIC, or first 24 channels) - [2] - IRQ for second ASIC (pcmuio96 only - IRQ for chans 48-72 .. can be the same as first irq!) -*/ + * Driver: pcmuio + * Description: Winsystems PC-104 based 48/96-channel DIO boards. + * Devices: (Winsystems) PCM-UIO48A [pcmuio48] + * (Winsystems) PCM-UIO96A [pcmuio96] + * Author: Calin Culianu <calin@ajvar.org> + * Updated: Fri, 13 Jan 2006 12:01:01 -0500 + * Status: works + * + * A driver for the relatively straightforward-to-program PCM-UIO48A and + * PCM-UIO96A boards from Winsystems. These boards use either one or two + * (in the 96-DIO version) WS16C48 ASIC HighDensity I/O Chips (HDIO). This + * chip is interesting in that each I/O line is individually programmable + * for INPUT or OUTPUT (thus comedi_dio_config can be done on a per-channel + * basis). Also, each chip supports edge-triggered interrupts for the first + * 24 I/O lines. Of course, since the 96-channel version of the board has + * two ASICs, it can detect polarity changes on up to 48 I/O lines. Since + * this is essentially an (non-PnP) ISA board, I/O Address and IRQ selection + * are done through jumpers on the board. You need to pass that information + * to this driver as the first and second comedi_config option, respectively. + * Note that the 48-channel version uses 16 bytes of IO memory and the 96- + * channel version uses 32-bytes (in case you are worried about conflicts). + * The 48-channel board is split into two 24-channel comedi subdevices. The + * 96-channel board is split into 4 24-channel DIO subdevices. + * + * Note that IRQ support has been added, but it is untested. + * + * To use edge-detection IRQ support, pass the IRQs of both ASICS (for the + * 96 channel version) or just 1 ASIC (for 48-channel version). Then, use + * comedi_commands with TRIG_NOW. Your callback will be called each time an + * edge is triggered, and the data values will be two sample_t's, which + * should be concatenated to form one 32-bit unsigned int. This value is + * the mask of channels that had edges detected from your channel list. Note + * that the bits positions in the mask correspond to positions in your + * chanlist when you specified the command and *not* channel id's! + * + * To set the polarity of the edge-detection interrupts pass a nonzero value + * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero value for + * both CR_RANGE and CR_AREF if you want edge-down polarity. + * + * In the 48-channel version: + * + * On subdev 0, the first 24 channels channels are edge-detect channels. + * + * In the 96-channel board you have the following channels that can do edge + * detection: + * + * subdev 0, channels 0-24 (first 24 channels of 1st ASIC) + * subdev 2, channels 0-24 (first 24 channels of 2nd ASIC) + * + * Configuration Options: + * [0] - I/O port base address + * [1] - IRQ (for first ASIC, or first 24 channels) + * [2] - IRQ (for second ASIC, pcmuio96 only - IRQ for chans 48-72 + * can be the same as first irq!) + */ +#include <linux/module.h> #include <linux/interrupt.h> -#include <linux/slab.h> + #include "../comedidev.h" -#include "pcm_common.h" - -#include <linux/pci.h> /* for PCI devices */ - -#define CHANS_PER_PORT 8 -#define PORTS_PER_ASIC 6 -#define INTR_PORTS_PER_ASIC 3 -#define MAX_CHANS_PER_SUBDEV 24 /* number of channels per comedi subdevice */ -#define PORTS_PER_SUBDEV (MAX_CHANS_PER_SUBDEV/CHANS_PER_PORT) -#define CHANS_PER_ASIC (CHANS_PER_PORT*PORTS_PER_ASIC) -#define INTR_CHANS_PER_ASIC 24 -#define INTR_PORTS_PER_SUBDEV (INTR_CHANS_PER_ASIC/CHANS_PER_PORT) -#define MAX_DIO_CHANS (PORTS_PER_ASIC*2*CHANS_PER_PORT) -#define MAX_ASICS (MAX_DIO_CHANS/CHANS_PER_ASIC) -#define SDEV_NO ((int)(s - dev->subdevices)) -#define CALC_N_SUBDEVS(nchans) ((nchans)/MAX_CHANS_PER_SUBDEV + (!!((nchans)%MAX_CHANS_PER_SUBDEV)) /*+ (nchans > INTR_CHANS_PER_ASIC ? 2 : 1)*/) -/* IO Memory sizes */ -#define ASIC_IOSIZE (0x10) -#define PCMUIO48_IOSIZE ASIC_IOSIZE -#define PCMUIO96_IOSIZE (ASIC_IOSIZE*2) - -/* Some offsets - these are all in the 16byte IO memory offset from - the base address. Note that there is a paging scheme to swap out - offsets 0x8-0xA using the PAGELOCK register. See the table below. - - Register(s) Pages R/W? Description - -------------------------------------------------------------- - REG_PORTx All R/W Read/Write/Configure IO - REG_INT_PENDING All ReadOnly Quickly see which INT_IDx has int. - REG_PAGELOCK All WriteOnly Select a page - REG_POLx Pg. 1 only WriteOnly Select edge-detection polarity - REG_ENABx Pg. 2 only WriteOnly Enable/Disable edge-detect. int. - REG_INT_IDx Pg. 3 only R/W See which ports/bits have ints. - */ -#define REG_PORT0 0x0 -#define REG_PORT1 0x1 -#define REG_PORT2 0x2 -#define REG_PORT3 0x3 -#define REG_PORT4 0x4 -#define REG_PORT5 0x5 -#define REG_INT_PENDING 0x6 -#define REG_PAGELOCK 0x7 /* page selector register, upper 2 bits select a page - and bits 0-5 are used to 'lock down' a particular - port above to make it readonly. */ -#define REG_POL0 0x8 -#define REG_POL1 0x9 -#define REG_POL2 0xA -#define REG_ENAB0 0x8 -#define REG_ENAB1 0x9 -#define REG_ENAB2 0xA -#define REG_INT_ID0 0x8 -#define REG_INT_ID1 0x9 -#define REG_INT_ID2 0xA - -#define NUM_PAGED_REGS 3 -#define NUM_PAGES 4 -#define FIRST_PAGED_REG 0x8 -#define REG_PAGE_BITOFFSET 6 -#define REG_LOCK_BITOFFSET 0 -#define REG_PAGE_MASK (~((0x1<<REG_PAGE_BITOFFSET)-1)) -#define REG_LOCK_MASK ~(REG_PAGE_MASK) -#define PAGE_POL 1 -#define PAGE_ENAB 2 -#define PAGE_INT_ID 3 + +#include "comedi_fc.h" /* - * 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. + * Register I/O map + * + * Offset Page 0 Page 1 Page 2 Page 3 + * ------ ----------- ----------- ----------- ----------- + * 0x00 Port 0 I/O Port 0 I/O Port 0 I/O Port 0 I/O + * 0x01 Port 1 I/O Port 1 I/O Port 1 I/O Port 1 I/O + * 0x02 Port 2 I/O Port 2 I/O Port 2 I/O Port 2 I/O + * 0x03 Port 3 I/O Port 3 I/O Port 3 I/O Port 3 I/O + * 0x04 Port 4 I/O Port 4 I/O Port 4 I/O Port 4 I/O + * 0x05 Port 5 I/O Port 5 I/O Port 5 I/O Port 5 I/O + * 0x06 INT_PENDING INT_PENDING INT_PENDING INT_PENDING + * 0x07 Page/Lock Page/Lock Page/Lock Page/Lock + * 0x08 N/A POL_0 ENAB_0 INT_ID0 + * 0x09 N/A POL_1 ENAB_1 INT_ID1 + * 0x0a N/A POL_2 ENAB_2 INT_ID2 */ +#define PCMUIO_PORT_REG(x) (0x00 + (x)) +#define PCMUIO_INT_PENDING_REG 0x06 +#define PCMUIO_PAGE_LOCK_REG 0x07 +#define PCMUIO_LOCK_PORT(x) ((1 << (x)) & 0x3f) +#define PCMUIO_PAGE(x) (((x) & 0x3) << 6) +#define PCMUIO_PAGE_MASK PCMUIO_PAGE(3) +#define PCMUIO_PAGE_POL 1 +#define PCMUIO_PAGE_ENAB 2 +#define PCMUIO_PAGE_INT_ID 3 +#define PCMUIO_PAGE_REG(x) (0x08 + (x)) + +#define PCMUIO_ASIC_IOSIZE 0x10 +#define PCMUIO_MAX_ASICS 2 + struct pcmuio_board { const char *name; const int num_asics; - const int num_channels_per_port; - const int num_ports; }; static const struct pcmuio_board pcmuio_boards[] = { { - .name = "pcmuio48", - .num_asics = 1, - .num_ports = 6, - }, - { - .name = "pcmuio96", - .num_asics = 2, - .num_ports = 12, - }, + .name = "pcmuio48", + .num_asics = 1, + }, { + .name = "pcmuio96", + .num_asics = 2, + }, }; -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct pcmuio_board *)dev->board_ptr) - -/* this structure is for data unique to this subdevice. */ -struct pcmuio_subdev_private { - /* mapping of halfwords (bytes) in port/chanarray to iobase */ - unsigned long iobases[PORTS_PER_SUBDEV]; - - /* The below is only used for intr subdevices */ - struct { - int asic; /* if non-negative, this subdev has an interrupt asic */ - int first_chan; /* if nonnegative, the first channel id for - interrupts. */ - int num_asic_chans; /* the number of asic channels in this subdev - that have interrutps */ - int asic_chan; /* if nonnegative, the first channel id with - respect to the asic that has interrupts */ - int enabled_mask; /* subdev-relative channel mask for channels - we are interested in */ - int active; - int stop_count; - int continuous; - spinlock_t spinlock; - } intr; +struct pcmuio_asic { + spinlock_t pagelock; /* protects the page registers */ + spinlock_t spinlock; /* protects member variables */ + unsigned int enabled_mask; + unsigned int stop_count; + unsigned int active:1; + unsigned int continuous:1; }; -/* 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 pcmuio_private { - struct { - unsigned char pagelock; /* current page and lock */ - unsigned char pol[NUM_PAGED_REGS]; /* shadow of POLx registers */ - unsigned char enab[NUM_PAGED_REGS]; /* shadow of ENABx registers */ - int num; - unsigned long iobase; - unsigned int irq; - spinlock_t spinlock; - } asics[MAX_ASICS]; - struct pcmuio_subdev_private *sprivs; -}; - -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct pcmuio_private *)dev->private) -#define subpriv ((struct pcmuio_subdev_private *)s->private) -/* - * 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 int pcmuio_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int pcmuio_detach(struct comedi_device *dev); - -static struct comedi_driver driver = { - .driver_name = "pcmuio", - .module = THIS_MODULE, - .attach = pcmuio_attach, - .detach = pcmuio_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 pcmuio_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 = &pcmuio_boards[0].name, - .offset = sizeof(struct pcmuio_board), - .num_names = ARRAY_SIZE(pcmuio_boards), + struct pcmuio_asic asics[PCMUIO_MAX_ASICS]; + unsigned int irq2; }; -static int pcmuio_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pcmuio_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static irqreturn_t interrupt_pcmuio(int irq, void *d); -static void pcmuio_stop_intr(struct comedi_device *, struct comedi_subdevice *); -static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); - -/* some helper functions to deal with specifics of this device's registers */ -static void init_asics(struct comedi_device *dev); /* sets up/clears ASIC chips to defaults */ -static void switch_page(struct comedi_device *dev, int asic, int page); -#ifdef notused -static void lock_port(struct comedi_device *dev, int asic, int port); -static void unlock_port(struct comedi_device *dev, int asic, int port); -#endif - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static inline unsigned long pcmuio_asic_iobase(struct comedi_device *dev, + int asic) { - struct comedi_subdevice *s; - int sdev_no, chans_left, n_subdevs, port, asic, thisasic_chanct = 0; - unsigned long iobase; - unsigned int irq[MAX_ASICS]; - - iobase = it->options[0]; - irq[0] = it->options[1]; - irq[1] = it->options[2]; - - printk("comedi%d: %s: io: %lx ", dev->minor, driver.driver_name, - iobase); - - dev->iobase = iobase; - - if (!iobase || !request_region(iobase, - thisboard->num_asics * ASIC_IOSIZE, - driver.driver_name)) { - printk("I/O port conflict\n"); - return -EIO; - } - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct pcmuio_private)) < 0) { - printk("cannot allocate private data structure\n"); - return -ENOMEM; - } - - for (asic = 0; asic < MAX_ASICS; ++asic) { - devpriv->asics[asic].num = asic; - devpriv->asics[asic].iobase = dev->iobase + asic * ASIC_IOSIZE; - devpriv->asics[asic].irq = 0; /* this gets actually set at the end of - this function when we - request_irqs */ - spin_lock_init(&devpriv->asics[asic].spinlock); - } + return dev->iobase + (asic * PCMUIO_ASIC_IOSIZE); +} - chans_left = CHANS_PER_ASIC * thisboard->num_asics; - n_subdevs = CALC_N_SUBDEVS(chans_left); - devpriv->sprivs = - kcalloc(n_subdevs, sizeof(struct pcmuio_subdev_private), - GFP_KERNEL); - if (!devpriv->sprivs) { - printk("cannot allocate subdevice private data structures\n"); - return -ENOMEM; - } +static inline int pcmuio_subdevice_to_asic(struct comedi_subdevice *s) +{ /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - * - * Allocate 2 subdevs (32 + 16 DIO lines) or 3 32 DIO subdevs for the - * 96-channel version of the board. + * subdevice 0 and 1 are handled by the first asic + * subdevice 2 and 3 are handled by the second asic */ - if (alloc_subdevices(dev, n_subdevs) < 0) { - printk("cannot allocate subdevice data structures\n"); - return -ENOMEM; - } - - port = 0; - asic = 0; - for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { - int byte_no; - - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; - s->maxdata = 1; - s->range_table = &range_digital; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->type = COMEDI_SUBD_DIO; - s->insn_bits = pcmuio_dio_insn_bits; - s->insn_config = pcmuio_dio_insn_config; - s->n_chan = min(chans_left, MAX_CHANS_PER_SUBDEV); - subpriv->intr.asic = -1; - subpriv->intr.first_chan = -1; - subpriv->intr.asic_chan = -1; - subpriv->intr.num_asic_chans = -1; - subpriv->intr.active = 0; - s->len_chanlist = 1; - - /* save the ioport address for each 'port' of 8 channels in the - subdevice */ - for (byte_no = 0; byte_no < PORTS_PER_SUBDEV; ++byte_no, ++port) { - if (port >= PORTS_PER_ASIC) { - port = 0; - ++asic; - thisasic_chanct = 0; - } - subpriv->iobases[byte_no] = - devpriv->asics[asic].iobase + port; - - if (thisasic_chanct < - CHANS_PER_PORT * INTR_PORTS_PER_ASIC - && subpriv->intr.asic < 0) { - /* this is an interrupt subdevice, so setup the struct */ - subpriv->intr.asic = asic; - subpriv->intr.active = 0; - subpriv->intr.stop_count = 0; - subpriv->intr.first_chan = byte_no * 8; - subpriv->intr.asic_chan = thisasic_chanct; - subpriv->intr.num_asic_chans = - s->n_chan - subpriv->intr.first_chan; - dev->read_subdev = s; - s->subdev_flags |= SDF_CMD_READ; - s->cancel = pcmuio_cancel; - s->do_cmd = pcmuio_cmd; - s->do_cmdtest = pcmuio_cmdtest; - s->len_chanlist = subpriv->intr.num_asic_chans; - } - thisasic_chanct += CHANS_PER_PORT; - } - spin_lock_init(&subpriv->intr.spinlock); - - chans_left -= s->n_chan; - - if (!chans_left) { - asic = 0; /* reset the asic to our first asic, to do intr subdevs */ - port = 0; - } - - } + return s->index / 2; +} - init_asics(dev); /* clear out all the registers, basically */ - - for (asic = 0; irq[0] && asic < MAX_ASICS; ++asic) { - if (irq[asic] - && request_irq(irq[asic], interrupt_pcmuio, - IRQF_SHARED, thisboard->name, dev)) { - int i; - /* unroll the allocated irqs.. */ - for (i = asic - 1; i >= 0; --i) { - free_irq(irq[i], dev); - devpriv->asics[i].irq = irq[i] = 0; - } - irq[asic] = 0; - } - devpriv->asics[asic].irq = irq[asic]; - } +static inline int pcmuio_subdevice_to_port(struct comedi_subdevice *s) +{ + /* + * subdevice 0 and 2 use port registers 0-2 + * subdevice 1 and 3 use port registers 3-5 + */ + return (s->index % 2) ? 3 : 0; +} - dev->irq = irq[0]; /* grr.. wish comedi dev struct supported multiple - irqs.. */ +static void pcmuio_write(struct comedi_device *dev, unsigned int val, + int asic, int page, int port) +{ + struct pcmuio_private *devpriv = dev->private; + struct pcmuio_asic *chip = &devpriv->asics[asic]; + unsigned long iobase = pcmuio_asic_iobase(dev, asic); + unsigned long flags; - if (irq[0]) { - printk("irq: %u ", irq[0]); - if (irq[1] && thisboard->num_asics == 2) - printk("second ASIC irq: %u ", irq[1]); + spin_lock_irqsave(&chip->pagelock, flags); + if (page == 0) { + /* Port registers are valid for any page */ + outb(val & 0xff, iobase + PCMUIO_PORT_REG(port + 0)); + outb((val >> 8) & 0xff, iobase + PCMUIO_PORT_REG(port + 1)); + outb((val >> 16) & 0xff, iobase + PCMUIO_PORT_REG(port + 2)); } else { - printk("(IRQ mode disabled) "); + outb(PCMUIO_PAGE(page), iobase + PCMUIO_PAGE_LOCK_REG); + outb(val & 0xff, iobase + PCMUIO_PAGE_REG(0)); + outb((val >> 8) & 0xff, iobase + PCMUIO_PAGE_REG(1)); + outb((val >> 16) & 0xff, iobase + PCMUIO_PAGE_REG(2)); } - - printk("attached\n"); - - return 1; + spin_unlock_irqrestore(&chip->pagelock, flags); } -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int pcmuio_detach(struct comedi_device *dev) +static unsigned int pcmuio_read(struct comedi_device *dev, + int asic, int page, int port) { - int i; - - printk("comedi%d: %s: remove\n", dev->minor, driver.driver_name); - if (dev->iobase) - release_region(dev->iobase, ASIC_IOSIZE * thisboard->num_asics); - - for (i = 0; i < MAX_ASICS; ++i) { - if (devpriv->asics[i].irq) - free_irq(devpriv->asics[i].irq, dev); + struct pcmuio_private *devpriv = dev->private; + struct pcmuio_asic *chip = &devpriv->asics[asic]; + unsigned long iobase = pcmuio_asic_iobase(dev, asic); + unsigned long flags; + unsigned int val; + + spin_lock_irqsave(&chip->pagelock, flags); + if (page == 0) { + /* Port registers are valid for any page */ + val = inb(iobase + PCMUIO_PORT_REG(port + 0)); + val |= (inb(iobase + PCMUIO_PORT_REG(port + 1)) << 8); + val |= (inb(iobase + PCMUIO_PORT_REG(port + 2)) << 16); + } else { + outb(PCMUIO_PAGE(page), iobase + PCMUIO_PAGE_LOCK_REG); + val = inb(iobase + PCMUIO_PAGE_REG(0)); + val |= (inb(iobase + PCMUIO_PAGE_REG(1)) << 8); + val |= (inb(iobase + PCMUIO_PAGE_REG(2)) << 16); } + spin_unlock_irqrestore(&chip->pagelock, flags); - if (devpriv && devpriv->sprivs) - kfree(devpriv->sprivs); - - return 0; + return val; } -/* DIO devices are slightly special. Although it is possible to - * implement the insn_read/insn_write interface, it is much more - * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ +/* + * Each channel can be individually programmed for input or output. + * Writing a '0' to a channel causes the corresponding output pin + * to go to a high-z state (pulled high by an external 10K resistor). + * This allows it to be used as an input. When used in the input mode, + * a read reflects the inverted state of the I/O pin, such that a + * high on the pin will read as a '0' in the register. Writing a '1' + * to a bit position causes the pin to sink current (up to 12mA), + * effectively pulling it low. + */ static int pcmuio_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int byte_no; - if (insn->n != 2) - return -EINVAL; - - /* NOTE: - reading a 0 means this channel was high - writine a 0 sets the channel high - reading a 1 means this channel was low - writing a 1 means set this channel low - - Therefore everything is always inverted. */ - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk("write mask: %08x data: %08x\n", data[0], data[1]); -#endif - - s->state = 0; - - for (byte_no = 0; byte_no < s->n_chan / CHANS_PER_PORT; ++byte_no) { - /* address of 8-bit port */ - unsigned long ioaddr = subpriv->iobases[byte_no], - /* bit offset of port in 32-bit doubleword */ - offset = byte_no * 8; - /* this 8-bit port's data */ - unsigned char byte = 0, - /* The write mask for this port (if any) */ - write_mask_byte = (data[0] >> offset) & 0xff, - /* The data byte for this port */ - data_byte = (data[1] >> offset) & 0xff; - - byte = inb(ioaddr); /* read all 8-bits for this port */ - -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk - ("byte %d wmb %02x db %02x offset %02d io %04x, data_in %02x ", - byte_no, (unsigned)write_mask_byte, (unsigned)data_byte, - offset, ioaddr, (unsigned)byte); -#endif - - if (write_mask_byte) { - /* this byte has some write_bits -- so set the output lines */ - byte &= ~write_mask_byte; /* clear bits for write mask */ - byte |= ~data_byte & write_mask_byte; /* set to inverted data_byte */ - /* Write out the new digital output state */ - outb(byte, ioaddr); - } -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk("data_out_byte %02x\n", (unsigned)byte); -#endif - /* save the digital input lines for this byte.. */ - s->state |= ((unsigned int)byte) << offset; + int asic = pcmuio_subdevice_to_asic(s); + int port = pcmuio_subdevice_to_port(s); + unsigned int chanmask = (1 << s->n_chan) - 1; + unsigned int mask; + unsigned int val; + + mask = comedi_dio_update_state(s, data); + if (mask) { + /* + * Outputs are inverted, invert the state and + * update the channels. + * + * The s->io_bits mask makes sure the input channels + * are '0' so that the outputs pins stay in a high + * z-state. + */ + val = ~s->state & chanmask; + val &= s->io_bits; + pcmuio_write(dev, val, asic, 0, port); } - /* now return the DIO lines to data[1] - note they came inverted! */ - data[1] = ~s->state; + /* get inverted state of the channels from the port */ + val = pcmuio_read(dev, asic, 0, port); -#ifdef DAMMIT_ITS_BROKEN - /* DEBUG */ - printk("s->state %08x data_out %08x\n", s->state, data[1]); -#endif + /* return the true state of the channels */ + data[1] = ~val & chanmask; - return 2; + return insn->n; } -/* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ static int pcmuio_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec), byte_no = chan / 8, bit_no = - chan % 8; - unsigned long ioaddr; - unsigned char byte; - - /* Compute ioaddr for this channel */ - ioaddr = subpriv->iobases[byte_no]; + int asic = pcmuio_subdevice_to_asic(s); + int port = pcmuio_subdevice_to_port(s); + int ret; - /* NOTE: - writing a 0 an IO channel's bit sets the channel to INPUT - and pulls the line high as well + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - writing a 1 to an IO channel's bit pulls the line low + if (data[0] == INSN_CONFIG_DIO_INPUT) + pcmuio_write(dev, s->io_bits, asic, 0, port); - All channels are implicitly always in OUTPUT mode -- but when - they are high they can be considered to be in INPUT mode.. - - Thus, we only force channels low if the config request was INPUT, - otherwise we do nothing to the hardware. */ + return insn->n; +} - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - /* save to io_bits -- don't actually do anything since - all input channels are also output channels... */ - s->io_bits |= 1 << chan; - break; - case INSN_CONFIG_DIO_INPUT: - /* write a 0 to the actual register representing the channel - to set it to 'input'. 0 means "float high". */ - byte = inb(ioaddr); - byte &= ~(1 << bit_no); - /**< set input channel to '0' */ - - /* write out byte -- this is the only time we actually affect the - hardware as all channels are implicitly output -- but input - channels are set to float-high */ - outb(byte, ioaddr); - - /* save to io_bits */ - s->io_bits &= ~(1 << chan); - break; +static void pcmuio_reset(struct comedi_device *dev) +{ + const struct pcmuio_board *board = comedi_board(dev); + int asic; - case INSN_CONFIG_DIO_QUERY: - /* retrieve from shadow register */ - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; + for (asic = 0; asic < board->num_asics; ++asic) { + /* first, clear all the DIO port bits */ + pcmuio_write(dev, 0, asic, 0, 0); + pcmuio_write(dev, 0, asic, 0, 3); - default: - return -EINVAL; - break; + /* Next, clear all the paged registers for each page */ + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_POL, 0); + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_ENAB, 0); + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0); } - - return insn->n; } -static void init_asics(struct comedi_device *dev) -{ /* sets up an - ASIC chip to defaults */ - int asic; +/* chip->spinlock is already locked */ +static void pcmuio_stop_intr(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pcmuio_private *devpriv = dev->private; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; - for (asic = 0; asic < thisboard->num_asics; ++asic) { - int port, page; - unsigned long baseaddr = dev->iobase + asic * ASIC_IOSIZE; + chip->enabled_mask = 0; + chip->active = 0; + s->async->inttrig = NULL; - switch_page(dev, asic, 0); /* switch back to page 0 */ + /* disable all intrs for this subdev.. */ + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_ENAB, 0); +} - /* first, clear all the DIO port bits */ - for (port = 0; port < PORTS_PER_ASIC; ++port) - outb(0, baseaddr + REG_PORT0 + port); +static void pcmuio_handle_intr_subdev(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned triggered) +{ + struct pcmuio_private *devpriv = dev->private; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned oldevents = s->async->events; + unsigned int val = 0; + unsigned long flags; + unsigned int i; - /* Next, clear all the paged registers for each page */ - for (page = 1; page < NUM_PAGES; ++page) { - int reg; - /* now clear all the paged registers */ - switch_page(dev, asic, page); - for (reg = FIRST_PAGED_REG; - reg < FIRST_PAGED_REG + NUM_PAGED_REGS; ++reg) - outb(0, baseaddr + reg); - } + spin_lock_irqsave(&chip->spinlock, flags); - /* DEBUG set rising edge interrupts on port0 of both asics */ - /*switch_page(dev, asic, PAGE_POL); - outb(0xff, baseaddr + REG_POL0); - switch_page(dev, asic, PAGE_ENAB); - outb(0xff, baseaddr + REG_ENAB0); */ - /* END DEBUG */ + if (!chip->active) + goto done; - switch_page(dev, asic, 0); /* switch back to default page 0 */ + if (!(triggered & chip->enabled_mask)) + goto done; + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + if (triggered & (1 << chan)) + val |= (1 << i); } -} -static void switch_page(struct comedi_device *dev, int asic, int page) -{ - if (asic < 0 || asic >= thisboard->num_asics) - return; /* paranoia */ - if (page < 0 || page >= NUM_PAGES) - return; /* more paranoia */ + /* Write the scan to the buffer. */ + if (comedi_buf_put(s, val) && + comedi_buf_put(s, val >> 16)) { + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + } else { + /* Overflow! Stop acquisition!! */ + /* TODO: STOP_ACQUISITION_CALL_HERE!! */ + pcmuio_stop_intr(dev, s); + } - devpriv->asics[asic].pagelock &= ~REG_PAGE_MASK; - devpriv->asics[asic].pagelock |= page << REG_PAGE_BITOFFSET; + /* Check for end of acquisition. */ + if (!chip->continuous) { + /* stop_src == TRIG_COUNT */ + if (chip->stop_count > 0) { + chip->stop_count--; + if (chip->stop_count == 0) { + s->async->events |= COMEDI_CB_EOA; + /* TODO: STOP_ACQUISITION_CALL_HERE!! */ + pcmuio_stop_intr(dev, s); + } + } + } - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); -} +done: + spin_unlock_irqrestore(&chip->spinlock, flags); -#ifdef notused -static void lock_port(struct comedi_device *dev, int asic, int port) -{ - if (asic < 0 || asic >= thisboard->num_asics) - return; /* paranoia */ - if (port < 0 || port >= PORTS_PER_ASIC) - return; /* more paranoia */ - - devpriv->asics[asic].pagelock |= 0x1 << port; - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); + if (oldevents != s->async->events) + comedi_event(dev, s); } -static void unlock_port(struct comedi_device *dev, int asic, int port) +static int pcmuio_handle_asic_interrupt(struct comedi_device *dev, int asic) { - if (asic < 0 || asic >= thisboard->num_asics) - return; /* paranoia */ - if (port < 0 || port >= PORTS_PER_ASIC) - return; /* more paranoia */ - devpriv->asics[asic].pagelock &= ~(0x1 << port) | REG_LOCK_MASK; - /* now write out the shadow register */ - outb(devpriv->asics[asic].pagelock, - dev->iobase + ASIC_IOSIZE * asic + REG_PAGELOCK); -} -#endif /* notused */ + /* there are could be two asics so we can't use dev->read_subdev */ + struct comedi_subdevice *s = &dev->subdevices[asic * 2]; + unsigned long iobase = pcmuio_asic_iobase(dev, asic); + unsigned int val; -static irqreturn_t interrupt_pcmuio(int irq, void *d) -{ - int asic, got1 = 0; - struct comedi_device *dev = (struct comedi_device *)d; - - for (asic = 0; asic < MAX_ASICS; ++asic) { - if (irq == devpriv->asics[asic].irq) { - unsigned long flags; - unsigned triggered = 0; - unsigned long iobase = devpriv->asics[asic].iobase; - /* it is an interrupt for ASIC #asic */ - unsigned char int_pend; - - spin_lock_irqsave(&devpriv->asics[asic].spinlock, - flags); - - int_pend = inb(iobase + REG_INT_PENDING) & 0x07; - - if (int_pend) { - int port; - for (port = 0; port < INTR_PORTS_PER_ASIC; - ++port) { - if (int_pend & (0x1 << port)) { - unsigned char - io_lines_with_edges = 0; - switch_page(dev, asic, - PAGE_INT_ID); - io_lines_with_edges = - inb(iobase + - REG_INT_ID0 + port); - - if (io_lines_with_edges) - /* clear pending interrupt */ - outb(0, iobase + - REG_INT_ID0 + - port); - - triggered |= - io_lines_with_edges << - port * 8; - } - } - - ++got1; - } + /* are there any interrupts pending */ + val = inb(iobase + PCMUIO_INT_PENDING_REG) & 0x07; + if (!val) + return 0; - spin_unlock_irqrestore(&devpriv->asics[asic].spinlock, - flags); - - if (triggered) { - struct comedi_subdevice *s; - /* TODO here: dispatch io lines to subdevs with commands.. */ - printk - ("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", - irq, asic, triggered); - for (s = dev->subdevices; - s < dev->subdevices + dev->n_subdevices; - ++s) { - if (subpriv->intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */ - unsigned long flags; - unsigned oldevents; - - spin_lock_irqsave(&subpriv-> - intr.spinlock, - flags); - - oldevents = s->async->events; - - if (subpriv->intr.active) { - unsigned mytrig = - ((triggered >> - subpriv->intr.asic_chan) - & - ((0x1 << subpriv-> - intr. - num_asic_chans) - - 1)) << subpriv-> - intr.first_chan; - if (mytrig & - subpriv->intr.enabled_mask) - { - unsigned int val - = 0; - unsigned int n, - ch, len; - - len = - s-> - async->cmd.chanlist_len; - for (n = 0; - n < len; - n++) { - ch = CR_CHAN(s->async->cmd.chanlist[n]); - if (mytrig & (1U << ch)) { - val |= (1U << n); - } - } - /* Write the scan to the buffer. */ - if (comedi_buf_put(s->async, ((short *)&val)[0]) - && - comedi_buf_put - (s->async, - ((short *) - &val)[1])) - { - s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); - } else { - /* Overflow! Stop acquisition!! */ - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmuio_stop_intr - (dev, - s); - } - - /* Check for end of acquisition. */ - if (!subpriv->intr.continuous) { - /* stop_src == TRIG_COUNT */ - if (subpriv->intr.stop_count > 0) { - subpriv->intr.stop_count--; - if (subpriv->intr.stop_count == 0) { - s->async->events |= COMEDI_CB_EOA; - /* TODO: STOP_ACQUISITION_CALL_HERE!! */ - pcmuio_stop_intr - (dev, - s); - } - } - } - } - } - - spin_unlock_irqrestore - (&subpriv->intr.spinlock, - flags); - - if (oldevents != - s->async->events) { - comedi_event(dev, s); - } - - } - - } - } + /* get, and clear, the pending interrupts */ + val = pcmuio_read(dev, asic, PCMUIO_PAGE_INT_ID, 0); + pcmuio_write(dev, 0, asic, PCMUIO_PAGE_INT_ID, 0); - } - } - if (!got1) - return IRQ_NONE; /* interrupt from other source */ - return IRQ_HANDLED; + /* handle the pending interrupts */ + pcmuio_handle_intr_subdev(dev, s, val); + + return 1; } -static void pcmuio_stop_intr(struct comedi_device *dev, - struct comedi_subdevice *s) +static irqreturn_t pcmuio_interrupt(int irq, void *d) { - int nports, firstport, asic, port; - - asic = subpriv->intr.asic; - if (asic < 0) - return; /* not an interrupt subdev */ - - subpriv->intr.enabled_mask = 0; - subpriv->intr.active = 0; - s->async->inttrig = 0; - nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - /* disable all intrs for this subdev.. */ - outb(0, devpriv->asics[asic].iobase + REG_ENAB0 + port); - } + struct comedi_device *dev = d; + struct pcmuio_private *devpriv = dev->private; + int handled = 0; + + if (irq == dev->irq) + handled += pcmuio_handle_asic_interrupt(dev, 0); + if (irq == devpriv->irq2) + handled += pcmuio_handle_asic_interrupt(dev, 1); + + return handled ? IRQ_HANDLED : IRQ_NONE; } +/* chip->spinlock is already locked */ static int pcmuio_start_intr(struct comedi_device *dev, struct comedi_subdevice *s) { - if (!subpriv->intr.continuous && subpriv->intr.stop_count == 0) { + struct pcmuio_private *devpriv = dev->private; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int bits = 0; + unsigned int pol_bits = 0; + int i; + + if (!chip->continuous && chip->stop_count == 0) { /* An empty acquisition! */ s->async->events |= COMEDI_CB_EOA; - subpriv->intr.active = 0; + chip->active = 0; return 1; - } else { - unsigned bits = 0, pol_bits = 0, n; - int nports, firstport, asic, port; - struct comedi_cmd *cmd = &s->async->cmd; - - asic = subpriv->intr.asic; - if (asic < 0) - return 1; /* not an interrupt - subdev */ - subpriv->intr.enabled_mask = 0; - subpriv->intr.active = 1; - nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; - firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; - if (cmd->chanlist) { - for (n = 0; n < cmd->chanlist_len; n++) { - bits |= (1U << CR_CHAN(cmd->chanlist[n])); - pol_bits |= (CR_AREF(cmd->chanlist[n]) - || CR_RANGE(cmd-> - chanlist[n]) ? 1U : 0U) - << CR_CHAN(cmd->chanlist[n]); - } - } - bits &= ((0x1 << subpriv->intr.num_asic_chans) - - 1) << subpriv->intr.first_chan; - subpriv->intr.enabled_mask = bits; - - switch_page(dev, asic, PAGE_ENAB); - for (port = firstport; port < firstport + nports; ++port) { - unsigned enab = - bits >> (subpriv->intr.first_chan + (port - - firstport) * - 8) & 0xff, pol = - pol_bits >> (subpriv->intr.first_chan + - (port - firstport) * 8) & 0xff; - /* set enab intrs for this subdev.. */ - outb(enab, - devpriv->asics[asic].iobase + REG_ENAB0 + port); - switch_page(dev, asic, PAGE_POL); - outb(pol, - devpriv->asics[asic].iobase + REG_ENAB0 + port); + } + + chip->enabled_mask = 0; + chip->active = 1; + if (cmd->chanlist) { + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chanspec = cmd->chanlist[i]; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + + bits |= (1 << chan); + pol_bits |= ((aref || range) ? 1 : 0) << chan; } } + bits &= ((1 << s->n_chan) - 1); + chip->enabled_mask = bits; + + /* set pol and enab intrs for this subdev.. */ + pcmuio_write(dev, pol_bits, asic, PCMUIO_PAGE_POL, 0); + pcmuio_write(dev, bits, asic, PCMUIO_PAGE_ENAB, 0); + return 0; } static int pcmuio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcmuio_private *devpriv = dev->private; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; - spin_lock_irqsave(&subpriv->intr.spinlock, flags); - if (subpriv->intr.active) + spin_lock_irqsave(&chip->spinlock, flags); + if (chip->active) pcmuio_stop_intr(dev, s); - spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); + spin_unlock_irqrestore(&chip->spinlock, flags); return 0; } -/* - * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice. - */ -static int -pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) +static int pcmuio_inttrig_start_intr(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) { + struct pcmuio_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; int event = 0; - if (trignum != 0) + if (trig_num != cmd->start_arg) return -EINVAL; - spin_lock_irqsave(&subpriv->intr.spinlock, flags); - s->async->inttrig = 0; - if (subpriv->intr.active) { + spin_lock_irqsave(&chip->spinlock, flags); + s->async->inttrig = NULL; + if (chip->active) event = pcmuio_start_intr(dev, s); - } - spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); - if (event) { + spin_unlock_irqrestore(&chip->spinlock, flags); + + if (event) comedi_event(dev, s); - } return 1; } @@ -968,68 +492,198 @@ pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, */ static int pcmuio_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pcmuio_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; + int asic = pcmuio_subdevice_to_asic(s); + struct pcmuio_asic *chip = &devpriv->asics[asic]; unsigned long flags; int event = 0; - spin_lock_irqsave(&subpriv->intr.spinlock, flags); - subpriv->intr.active = 1; + spin_lock_irqsave(&chip->spinlock, flags); + chip->active = 1; /* Set up end of acquisition. */ switch (cmd->stop_src) { case TRIG_COUNT: - subpriv->intr.continuous = 0; - subpriv->intr.stop_count = cmd->stop_arg; + chip->continuous = 0; + chip->stop_count = cmd->stop_arg; break; default: /* TRIG_NONE */ - subpriv->intr.continuous = 1; - subpriv->intr.stop_count = 0; + chip->continuous = 1; + chip->stop_count = 0; break; } /* Set up start of acquisition. */ - switch (cmd->start_src) { - case TRIG_INT: + if (cmd->start_src == TRIG_INT) s->async->inttrig = pcmuio_inttrig_start_intr; - break; - default: - /* TRIG_NOW */ + else /* TRIG_NOW */ event = pcmuio_start_intr(dev, s); - break; - } - spin_unlock_irqrestore(&subpriv->intr.spinlock, flags); - if (event) { + spin_unlock_irqrestore(&chip->spinlock, flags); + + if (event) comedi_event(dev, s); - } return 0; } -static int -pcmuio_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd) +static int pcmuio_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { - return comedi_pcm_cmdtest(dev, s, cmd); + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) + return 1; + + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_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); + 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); + + switch (cmd->stop_src) { + case TRIG_COUNT: + /* any count allowed */ + break; + case TRIG_NONE: + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + break; + default: + break; + } + + if (err) + return 3; + + /* step 4: fix up any arguments */ + + /* if (err) return 4; */ + + return 0; } -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_init_module(void) +static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - return comedi_driver_register(&driver); + const struct pcmuio_board *board = comedi_board(dev); + struct comedi_subdevice *s; + struct pcmuio_private *devpriv; + int ret; + int i; + + ret = comedi_request_region(dev, it->options[0], + board->num_asics * PCMUIO_ASIC_IOSIZE); + if (ret) + return ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + for (i = 0; i < PCMUIO_MAX_ASICS; ++i) { + struct pcmuio_asic *chip = &devpriv->asics[i]; + + spin_lock_init(&chip->pagelock); + spin_lock_init(&chip->spinlock); + } + + pcmuio_reset(dev); + + if (it->options[1]) { + /* request the irq for the 1st asic */ + ret = request_irq(it->options[1], pcmuio_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + dev->irq = it->options[1]; + } + + if (board->num_asics == 2) { + if (it->options[2] == dev->irq) { + /* the same irq (or none) is used by both asics */ + devpriv->irq2 = it->options[2]; + } else if (it->options[2]) { + /* request the irq for the 2nd asic */ + ret = request_irq(it->options[2], pcmuio_interrupt, 0, + dev->board_name, dev); + if (ret == 0) + devpriv->irq2 = it->options[2]; + } + } + + ret = comedi_alloc_subdevices(dev, board->num_asics * 2); + if (ret) + return ret; + + for (i = 0; i < dev->n_subdevices; ++i) { + s = &dev->subdevices[i]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 24; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pcmuio_dio_insn_bits; + s->insn_config = pcmuio_dio_insn_config; + + /* subdevices 0 and 2 can suppport interrupts */ + if ((i == 0 && dev->irq) || (i == 2 && devpriv->irq2)) { + /* setup the interrupt subdevice */ + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->len_chanlist = s->n_chan; + s->cancel = pcmuio_cancel; + s->do_cmd = pcmuio_cmd; + s->do_cmdtest = pcmuio_cmdtest; + } + } + + return 0; } -static void __exit driver_cleanup_module(void) +static void pcmuio_detach(struct comedi_device *dev) { - comedi_driver_unregister(&driver); + struct pcmuio_private *devpriv = dev->private; + + if (devpriv) { + pcmuio_reset(dev); + + /* free the 2nd irq if used, the core will free the 1st one */ + if (devpriv->irq2 && devpriv->irq2 != dev->irq) + free_irq(devpriv->irq2, dev); + } + comedi_legacy_detach(dev); } -module_init(driver_init_module); -module_exit(driver_cleanup_module); +static struct comedi_driver pcmuio_driver = { + .driver_name = "pcmuio", + .module = THIS_MODULE, + .attach = pcmuio_attach, + .detach = pcmuio_detach, + .board_name = &pcmuio_boards[0].name, + .offset = sizeof(struct pcmuio_board), + .num_names = ARRAY_SIZE(pcmuio_boards), +}; +module_comedi_driver(pcmuio_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/plx9052.h b/drivers/staging/comedi/drivers/plx9052.h index 5894739ff42..fbcf2506980 100644 --- a/drivers/staging/comedi/drivers/plx9052.h +++ b/drivers/staging/comedi/drivers/plx9052.h @@ -16,71 +16,64 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #ifndef _PLX9052_H_ #define _PLX9052_H_ /* - * PLX PCI9052 INTCSR register. + * INTCSR - Interrupt Control/Status register + */ +#define PLX9052_INTCSR 0x4c +#define PLX9052_INTCSR_LI1ENAB (1 << 0) /* LI1 enabled */ +#define PLX9052_INTCSR_LI1POL (1 << 1) /* LI1 active high */ +#define PLX9052_INTCSR_LI1STAT (1 << 2) /* LI1 active */ +#define PLX9052_INTCSR_LI2ENAB (1 << 3) /* LI2 enabled */ +#define PLX9052_INTCSR_LI2POL (1 << 4) /* LI2 active high */ +#define PLX9052_INTCSR_LI2STAT (1 << 5) /* LI2 active */ +#define PLX9052_INTCSR_PCIENAB (1 << 6) /* PCIINT enabled */ +#define PLX9052_INTCSR_SOFTINT (1 << 7) /* generate soft int */ +#define PLX9052_INTCSR_LI1SEL (1 << 8) /* LI1 edge */ +#define PLX9052_INTCSR_LI2SEL (1 << 9) /* LI2 edge */ +#define PLX9052_INTCSR_LI1CLRINT (1 << 10) /* LI1 clear int */ +#define PLX9052_INTCSR_LI2CLRINT (1 << 11) /* LI2 clear int */ +#define PLX9052_INTCSR_ISAMODE (1 << 12) /* ISA interface mode */ + +/* + * CNTRL - User I/O, Direct Slave Response, Serial EEPROM, and + * Initialization Control register */ -#define PLX9052_INTCSR 0x4C /* Offset in Local Configuration Registers */ -/* Local Interrupt 1 Enable */ -#define PLX9052_INTCSR_LI1ENAB_MASK 0x0001 -#define PLX9052_INTCSR_LI1ENAB_DISABLED 0x0000 -#define PLX9052_INTCSR_LI1ENAB_ENABLED 0x0001 -/* Local Interrupt 1 Polarity */ -#define PLX9052_INTCSR_LI1POL_MASK 0x0002 -#define PLX9052_INTCSR_LI1POL_LOW 0x0000 -#define PLX9052_INTCSR_LI1POL_HIGH 0x0002 -/* Local Interrupt 1 Status (read-only) */ -#define PLX9052_INTCSR_LI1STAT_MASK 0x0004 -#define PLX9052_INTCSR_LI1STAT_INACTIVE 0x0000 -#define PLX9052_INTCSR_LI1STAT_ACTIVE 0x0004 -/* Local Interrupt 2 Enable */ -#define PLX9052_INTCSR_LI2ENAB_MASK 0x0008 -#define PLX9052_INTCSR_LI2ENAB_DISABLED 0x0000 -#define PLX9052_INTCSR_LI2ENAB_ENABLED 0x0008 -/* Local Interrupt 2 Polarity */ -#define PLX9052_INTCSR_LI2POL_MASK 0x0010 -#define PLX9052_INTCSR_LI2POL_LOW 0x0000 -#define PLX9052_INTCSR_LI2POL_HIGH 0x0010 -/* Local Interrupt 2 Status (read-only) */ -#define PLX9052_INTCSR_LI2STAT_MASK 0x0020 -#define PLX9052_INTCSR_LI2STAT_INACTIVE 0x0000 -#define PLX9052_INTCSR_LI2STAT_ACTIVE 0x0020 -/* PCI Interrupt Enable */ -#define PLX9052_INTCSR_PCIENAB_MASK 0x0040 -#define PLX9052_INTCSR_PCIENAB_DISABLED 0x0000 -#define PLX9052_INTCSR_PCIENAB_ENABLED 0x0040 -/* Software Interrupt */ -#define PLX9052_INTCSR_SOFTINT_MASK 0x0080 -#define PLX9052_INTCSR_SOFTINT_UNASSERTED 0x0000 -#define PLX9052_INTCSR_SOFTINT_ASSERTED 0x0080 -/* Local Interrupt 1 Select Enable */ -#define PLX9052_INTCSR_LI1SEL_MASK 0x0100 -#define PLX9052_INTCSR_LI1SEL_LEVEL 0x0000 -#define PLX9052_INTCSR_LI1SEL_EDGE 0x0100 -/* Local Interrupt 2 Select Enable */ -#define PLX9052_INTCSR_LI2SEL_MASK 0x0200 -#define PLX9052_INTCSR_LI2SEL_LEVEL 0x0000 -#define PLX9052_INTCSR_LI2SEL_EDGE 0x0200 -/* Local Edge Triggerable Interrupt 1 Clear Bit */ -#define PLX9052_INTCSR_LI1CLRINT_MASK 0x0400 -#define PLX9052_INTCSR_LI1CLRINT_UNASSERTED 0x0000 -#define PLX9052_INTCSR_LI1CLRINT_ASSERTED 0x0400 -/* Local Edge Triggerable Interrupt 2 Clear Bit */ -#define PLX9052_INTCSR_LI2CLRINT_MASK 0x0800 -#define PLX9052_INTCSR_LI2CLRINT_UNASSERTED 0x0000 -#define PLX9052_INTCSR_LI2CLRINT_ASSERTED 0x0800 -/* ISA Interface Mode Enable (read-only over PCI bus) */ -#define PLX9052_INTCSR_ISAMODE_MASK 0x1000 -#define PLX9052_INTCSR_ISAMODE_DISABLED 0x0000 -#define PLX9052_INTCSR_ISAMODE_ENABLED 0x1000 +#define PLX9052_CNTRL 0x50 +#define PLX9052_CNTRL_WAITO (1 << 0) /* UIO0 or WAITO# select */ +#define PLX9052_CNTRL_UIO0_DIR (1 << 1) /* UIO0 direction */ +#define PLX9052_CNTRL_UIO0_DATA (1 << 2) /* UIO0 data */ +#define PLX9052_CNTRL_LLOCKO (1 << 3) /* UIO1 or LLOCKo# select */ +#define PLX9052_CNTRL_UIO1_DIR (1 << 4) /* UIO1 direction */ +#define PLX9052_CNTRL_UIO1_DATA (1 << 5) /* UIO1 data */ +#define PLX9052_CNTRL_CS2 (1 << 6) /* UIO2 or CS2# select */ +#define PLX9052_CNTRL_UIO2_DIR (1 << 7) /* UIO2 direction */ +#define PLX9052_CNTRL_UIO2_DATA (1 << 8) /* UIO2 data */ +#define PLX9052_CNTRL_CS3 (1 << 9) /* UIO3 or CS3# select */ +#define PLX9052_CNTRL_UIO3_DIR (1 << 10) /* UIO3 direction */ +#define PLX9052_CNTRL_UIO3_DATA (1 << 11) /* UIO3 data */ +#define PLX9052_CNTRL_PCIBAR01 (0 << 12) /* bar 0 (mem) and 1 (I/O) */ +#define PLX9052_CNTRL_PCIBAR0 (1 << 12) /* bar 0 (mem) only */ +#define PLX9052_CNTRL_PCIBAR1 (2 << 12) /* bar 1 (I/O) only */ +#define PLX9052_CNTRL_PCI2_1_FEATURES (1 << 14) /* PCI r2.1 features enabled */ +#define PLX9052_CNTRL_PCI_R_W_FLUSH (1 << 15) /* read w/write flush mode */ +#define PLX9052_CNTRL_PCI_R_NO_FLUSH (1 << 16) /* read no flush mode */ +#define PLX9052_CNTRL_PCI_R_NO_WRITE (1 << 17) /* read no write mode */ +#define PLX9052_CNTRL_PCI_W_RELEASE (1 << 18) /* write release bus mode */ +#define PLX9052_CNTRL_RETRY_CLKS(x) (((x) & 0xf) << 19) /* slave retry clks */ +#define PLX9052_CNTRL_LOCK_ENAB (1 << 23) /* slave LOCK# enable */ +#define PLX9052_CNTRL_EEPROM_MASK (0x1f << 24) /* EEPROM bits */ +#define PLX9052_CNTRL_EEPROM_CLK (1 << 24) /* EEPROM clock */ +#define PLX9052_CNTRL_EEPROM_CS (1 << 25) /* EEPROM chip select */ +#define PLX9052_CNTRL_EEPROM_DOUT (1 << 26) /* EEPROM write bit */ +#define PLX9052_CNTRL_EEPROM_DIN (1 << 27) /* EEPROM read bit */ +#define PLX9052_CNTRL_EEPROM_PRESENT (1 << 28) /* EEPROM present */ +#define PLX9052_CNTRL_RELOAD_CFG (1 << 29) /* reload configuration */ +#define PLX9052_CNTRL_PCI_RESET (1 << 30) /* PCI adapter reset */ +#define PLX9052_CNTRL_MASK_REV (1 << 31) /* mask revision */ #endif /* _PLX9052_H_ */ diff --git a/drivers/staging/comedi/drivers/plx9080.h b/drivers/staging/comedi/drivers/plx9080.h index 0d254a1b78a..25706531b88 100644 --- a/drivers/staging/comedi/drivers/plx9080.h +++ b/drivers/staging/comedi/drivers/plx9080.h @@ -29,13 +29,13 @@ /* descriptor block used for chained dma transfers */ struct plx_dma_desc { - volatile uint32_t pci_start_addr; - volatile uint32_t local_start_addr; + __le32 pci_start_addr; + __le32 local_start_addr; /* transfer_size is in bytes, only first 23 bits of register are used */ - volatile uint32_t transfer_size; + __le32 transfer_size; /* address of next descriptor (quad word aligned), plus some * additional bits (see PLX_DMA0_DESCRIPTOR_REG) */ - volatile uint32_t next; + __le32 next; }; /********************************************************************** @@ -402,12 +402,9 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) udelay(1); dma_status = readb(dma_cs_addr); } - if (i == timeout) { - printk - ("plx9080: cancel() timed out waiting for dma %i done clear\n", - channel); + if (i == timeout) return -ETIMEDOUT; - } + /* disable and abort channel */ writeb(PLX_DMA_ABORT_BIT, dma_cs_addr); /* wait for dma done bit */ @@ -416,12 +413,8 @@ static inline int plx9080_abort_dma(void __iomem *iobase, unsigned int channel) udelay(1); dma_status = readb(dma_cs_addr); } - if (i == timeout) { - printk - ("plx9080: cancel() timed out waiting for dma %i done set\n", - channel); + if (i == timeout) return -ETIMEDOUT; - } return 0; } diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c deleted file mode 100644 index 831a576c24a..00000000000 --- a/drivers/staging/comedi/drivers/poc.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - comedi/drivers/poc.c - Mini-drivers for POC (Piece of Crap) boards - Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net> - Copyright (C) 2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* -Driver: poc -Description: Generic driver for very simple devices -Author: ds -Devices: [Keithley Metrabyte] DAC-02 (dac02), [Advantech] PCL-733 (pcl733), - PCL-734 (pcl734) -Updated: Sat, 16 Mar 2002 17:34:48 -0800 -Status: unknown - -This driver is indended to support very simple ISA-based devices, -including: - dac02 - Keithley DAC-02 analog output board - pcl733 - Advantech PCL-733 - pcl734 - Advantech PCL-734 - -Configuration options: - [0] - I/O port base -*/ - -#include "../comedidev.h" - -#include <linux/ioport.h> - -static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int poc_detach(struct comedi_device *dev); -static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pcl733_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int pcl734_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -struct boarddef_struct { - const char *name; - unsigned int iosize; - int (*setup) (struct comedi_device *); - int type; - int n_chan; - int n_bits; - int (*winsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*rinsn) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - int (*insnbits) (struct comedi_device *, struct comedi_subdevice *, - struct comedi_insn *, unsigned int *); - const struct comedi_lrange *range; -}; -static const struct boarddef_struct boards[] = { - { - .name = "dac02", - .iosize = 8, - /* .setup = dac02_setup, */ - .type = COMEDI_SUBD_AO, - .n_chan = 2, - .n_bits = 12, - .winsn = dac02_ao_winsn, - .rinsn = readback_insn, - .range = &range_unknown, - }, - { - .name = "pcl733", - .iosize = 4, - .type = COMEDI_SUBD_DI, - .n_chan = 32, - .n_bits = 1, - .insnbits = pcl733_insn_bits, - .range = &range_digital, - }, - { - .name = "pcl734", - .iosize = 4, - .type = COMEDI_SUBD_DO, - .n_chan = 32, - .n_bits = 1, - .insnbits = pcl734_insn_bits, - .range = &range_digital, - }, -}; - -#define n_boards ARRAY_SIZE(boards) -#define this_board ((const struct boarddef_struct *)dev->board_ptr) - -static struct comedi_driver driver_poc = { - .driver_name = "poc", - .module = THIS_MODULE, - .attach = poc_attach, - .detach = poc_detach, - .board_name = &boards[0].name, - .num_names = n_boards, - .offset = sizeof(boards[0]), -}; - -static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - unsigned long iobase; - unsigned int iosize; - - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: poc: using %s iobase 0x%lx\n", dev->minor, - this_board->name, iobase); - - dev->board_name = this_board->name; - - if (iobase == 0) { - printk(KERN_ERR "io base address required\n"); - return -EINVAL; - } - - iosize = this_board->iosize; - /* check if io addresses are available */ - if (!request_region(iobase, iosize, "dac02")) { - printk(KERN_ERR "I/O port conflict: failed to allocate ports " - "0x%lx to 0x%lx\n", iobase, iobase + iosize - 1); - return -EIO; - } - dev->iobase = iobase; - - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; - if (alloc_private(dev, sizeof(unsigned int) * this_board->n_chan) < 0) - return -ENOMEM; - - /* analog output subdevice */ - s = dev->subdevices + 0; - s->type = this_board->type; - s->n_chan = this_board->n_chan; - s->maxdata = (1 << this_board->n_bits) - 1; - s->range_table = this_board->range; - s->insn_write = this_board->winsn; - s->insn_read = this_board->rinsn; - s->insn_bits = this_board->insnbits; - if (s->type == COMEDI_SUBD_AO || s->type == COMEDI_SUBD_DO) - s->subdev_flags = SDF_WRITABLE; - - return 0; -} - -static int poc_detach(struct comedi_device *dev) -{ - /* only free stuff if it has been allocated by _attach */ - if (dev->iobase) - release_region(dev->iobase, this_board->iosize); - - printk(KERN_INFO "comedi%d: dac02: remove\n", dev->minor); - - return 0; -} - -static int readback_insn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int chan; - - chan = CR_CHAN(insn->chanspec); - data[0] = ((unsigned int *)dev->private)[chan]; - - return 1; -} - -/* DAC-02 registers */ -#define DAC02_LSB(a) (2 * a) -#define DAC02_MSB(a) (2 * a + 1) - -static int dac02_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int temp; - int chan; - int output; - - chan = CR_CHAN(insn->chanspec); - ((unsigned int *)dev->private)[chan] = data[0]; - output = data[0]; -#ifdef wrong - /* convert to complementary binary if range is bipolar */ - if ((CR_RANGE(insn->chanspec) & 0x2) == 0) - output = ~output; -#endif - temp = (output << 4) & 0xf0; - outb(temp, dev->iobase + DAC02_LSB(chan)); - temp = (output >> 4) & 0xff; - outb(temp, dev->iobase + DAC02_MSB(chan)); - - return 1; -} - -static int pcl733_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - - data[1] = inb(dev->iobase + 0); - data[1] |= (inb(dev->iobase + 1) << 8); - data[1] |= (inb(dev->iobase + 2) << 16); - data[1] |= (inb(dev->iobase + 3) << 24); - - return 2; -} - -static int pcl734_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - if (insn->n != 2) - return -EINVAL; - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - if ((data[0] >> 0) & 0xff) - outb((s->state >> 0) & 0xff, dev->iobase + 0); - if ((data[0] >> 8) & 0xff) - outb((s->state >> 8) & 0xff, dev->iobase + 1); - if ((data[0] >> 16) & 0xff) - outb((s->state >> 16) & 0xff, dev->iobase + 2); - if ((data[0] >> 24) & 0xff) - outb((s->state >> 24) & 0xff, dev->iobase + 3); - } - data[1] = s->state; - - return 2; -} - -static int __init driver_poc_init_module(void) -{ - return comedi_driver_register(&driver_poc); -} - -static void __exit driver_poc_cleanup_module(void) -{ - comedi_driver_unregister(&driver_poc); -} - -module_init(driver_poc_init_module); -module_exit(driver_poc_cleanup_module); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index e0bb73445dd..b3bbec0a0d2 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -47,6 +47,7 @@ Status: works Devices: [Quatech] DAQP-208 (daqp), DAQP-308 */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/semaphore.h> @@ -56,28 +57,18 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308 #include <linux/completion.h> -/* Maximum number of separate DAQP devices we'll allow */ -#define MAX_DEV 4 +#include "comedi_fc.h" -struct local_info_t { - struct pcmcia_device *link; +struct daqp_private { int stop; - int table_index; - char board_name[32]; enum { semaphore, buffer } interrupt_mode; struct completion eos; - struct comedi_device *dev; - struct comedi_subdevice *s; int count; }; -/* A list of "instances" of the device. */ - -static struct local_info_t *dev_table[MAX_DEV] = { NULL, /* ... */ }; - /* The DAQP communicates with the system through a 16 byte I/O window. */ #define DAQP_FIFO_SIZE 4096 @@ -161,84 +152,38 @@ static struct local_info_t *dev_table[MAX_DEV] = { NULL, /* ... */ }; #define DAQP_AUX_FIFO_NEARFULL 0x02 #define DAQP_AUX_FIFO_EMPTY 0x01 -/* These range structures tell COMEDI how the sample values map to - * voltages. The A/D converter has four .ranges = +/- 10V through - * +/- 1.25V, and the D/A converter has only .one = +/- 5V. - */ - -static const struct comedi_lrange range_daqp_ai = { 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25) - } -}; - -static const struct comedi_lrange range_daqp_ao = { 1, {BIP_RANGE(5)} }; - -/*====================================================================*/ - -/* comedi interface code */ - -static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int daqp_detach(struct comedi_device *dev); -static struct comedi_driver driver_daqp = { - .driver_name = "quatech_daqp_cs", - .module = THIS_MODULE, - .attach = daqp_attach, - .detach = daqp_detach, -}; - -#ifdef DAQP_DEBUG - -static void daqp_dump(struct comedi_device *dev) -{ - printk(KERN_INFO "DAQP: status %02x; aux status %02x\n", - inb(dev->iobase + DAQP_STATUS), inb(dev->iobase + DAQP_AUX)); -} - -static void hex_dump(char *str, void *ptr, int len) -{ - unsigned char *cptr = ptr; - int i; - - printk(str); - - for (i = 0; i < len; i++) { - if (i % 16 == 0) - printk("\n%p:", cptr); - - printk(" %02x", *(cptr++)); +static const struct comedi_lrange range_daqp_ai = { + 4, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25) } - printk("\n"); -} - -#endif +}; /* Cancel a running acquisition */ static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; - if (local->stop) + if (devpriv->stop) return -EIO; - outb(DAQP_COMMAND_STOP, dev->iobase + DAQP_COMMAND); /* flush any linguring data in FIFO - superfluous here */ /* outb(DAQP_COMMAND_RSTF, dev->iobase+DAQP_COMMAND); */ - local->interrupt_mode = semaphore; + devpriv->interrupt_mode = semaphore; return 0; } /* Interrupt handler * - * Operates in one of two modes. If local->interrupt_mode is - * 'semaphore', just signal the local->eos completion and return + * Operates in one of two modes. If devpriv->interrupt_mode is + * 'semaphore', just signal the devpriv->eos completion and return * (one-shot mode). Otherwise (continuous mode), read data in from * the card, transfer it to the buffer provided by the higher-level * comedi kernel module, and signal various comedi callback routines, @@ -246,62 +191,29 @@ static int daqp_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) */ static enum irqreturn daqp_interrupt(int irq, void *dev_id) { - struct local_info_t *local = (struct local_info_t *)dev_id; - struct comedi_device *dev; - struct comedi_subdevice *s; + struct comedi_device *dev = dev_id; + struct daqp_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; int loop_limit = 10000; int status; - if (local == NULL) { - printk(KERN_WARNING - "daqp_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } - - dev = local->dev; - if (dev == NULL) { - printk(KERN_WARNING "daqp_interrupt(): NULL comedi_device.\n"); - return IRQ_NONE; - } - - if (!dev->attached) { - printk(KERN_WARNING - "daqp_interrupt(): struct comedi_device not yet attached.\n"); - return IRQ_NONE; - } - - s = local->s; - if (s == NULL) { - printk(KERN_WARNING - "daqp_interrupt(): NULL comedi_subdevice.\n"); + if (!dev->attached) return IRQ_NONE; - } - - if ((struct local_info_t *)s->private != local) { - printk(KERN_WARNING - "daqp_interrupt(): invalid comedi_subdevice.\n"); - return IRQ_NONE; - } - - switch (local->interrupt_mode) { + switch (devpriv->interrupt_mode) { case semaphore: - - complete(&local->eos); + complete(&devpriv->eos); break; case buffer: - while (!((status = inb(dev->iobase + DAQP_STATUS)) & DAQP_STATUS_FIFO_EMPTY)) { - - short data; + unsigned short data; if (status & DAQP_STATUS_DATA_LOST) { s->async->events |= COMEDI_CB_EOA | COMEDI_CB_OVERFLOW; - printk("daqp: data lost\n"); - daqp_ai_cancel(dev, s); + dev_warn(dev->class_dev, "data lost\n"); break; } @@ -309,16 +221,15 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) data |= inb(dev->iobase + DAQP_FIFO) << 8; data ^= 0x8000; - comedi_buf_put(s->async, data); + comedi_buf_put(s, data); /* If there's a limit, decrement it * and stop conversion if zero */ - if (local->count > 0) { - local->count--; - if (local->count == 0) { - daqp_ai_cancel(dev, s); + if (devpriv->count > 0) { + devpriv->count--; + if (devpriv->count == 0) { s->async->events |= COMEDI_CB_EOA; break; } @@ -329,34 +240,53 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id) } if (loop_limit <= 0) { - printk(KERN_WARNING - "loop_limit reached in daqp_interrupt()\n"); - daqp_ai_cancel(dev, s); + dev_warn(dev->class_dev, + "loop_limit reached in daqp_interrupt()\n"); s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR; } s->async->events |= COMEDI_CB_BLOCK; - comedi_event(dev, s); + cfc_handle_events(dev, s); } return IRQ_HANDLED; } +static void daqp_ai_set_one_scanlist_entry(struct comedi_device *dev, + unsigned int chanspec, + int start) +{ + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); + unsigned int val; + + val = DAQP_SCANLIST_CHANNEL(chan) | DAQP_SCANLIST_GAIN(range); + + if (aref == AREF_DIFF) + val |= DAQP_SCANLIST_DIFFERENTIAL; + + if (start) + val |= DAQP_SCANLIST_START; + + outb(val & 0xff, dev->iobase + DAQP_SCANLIST); + outb((val >> 8) & 0xff, dev->iobase + DAQP_SCANLIST); +} + /* One-shot analog data acquisition routine */ static int daqp_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; int i; int v; int counter = 10000; - if (local->stop) + if (devpriv->stop) return -EIO; - /* Stop any running conversion */ daqp_ai_cancel(dev, s); @@ -366,18 +296,7 @@ static int daqp_ai_insn_read(struct comedi_device *dev, outb(DAQP_COMMAND_RSTQ, dev->iobase + DAQP_COMMAND); /* Program one scan list entry */ - - v = DAQP_SCANLIST_CHANNEL(CR_CHAN(insn->chanspec)) - | DAQP_SCANLIST_GAIN(CR_RANGE(insn->chanspec)); - - if (CR_AREF(insn->chanspec) == AREF_DIFF) - v |= DAQP_SCANLIST_DIFFERENTIAL; - - - v |= DAQP_SCANLIST_START; - - outb(v & 0xff, dev->iobase + DAQP_SCANLIST); - outb(v >> 8, dev->iobase + DAQP_SCANLIST); + daqp_ai_set_one_scanlist_entry(dev, insn->chanspec, 1); /* Reset data FIFO (see page 28 of DAQP User's Manual) */ @@ -395,16 +314,16 @@ static int daqp_ai_insn_read(struct comedi_device *dev, */ while (--counter - && (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) ; + && (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) + ; if (!counter) { - printk("daqp: couldn't clear interrupts in status register\n"); + dev_err(dev->class_dev, + "couldn't clear interrupts in status register\n"); return -1; } - init_completion(&local->eos); - local->interrupt_mode = semaphore; - local->dev = dev; - local->s = s; + init_completion(&devpriv->eos); + devpriv->interrupt_mode = semaphore; for (i = 0; i < insn->n; i++) { @@ -414,7 +333,7 @@ static int daqp_ai_insn_read(struct comedi_device *dev, /* Wait for interrupt service routine to unblock completion */ /* Maybe could use a timeout here, but it's interruptible */ - if (wait_for_completion_interruptible(&local->eos)) + if (wait_for_completion_interruptible(&devpriv->eos)) return -EINTR; data[i] = inb(dev->iobase + DAQP_FIFO); @@ -454,70 +373,41 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + unsigned int arg; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources - * are unique and mutually compatible - */ + /* 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); - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_NOW && cmd->convert_src != TRIG_TIMER) - err++; - if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } #define MAX_SPEED 10000 /* 100 kHz - in nanoseconds */ - if (cmd->scan_begin_src == TRIG_TIMER - && cmd->scan_begin_arg < MAX_SPEED) { - cmd->scan_begin_arg = MAX_SPEED; - err++; - } + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + MAX_SPEED); /* If both scan_begin and convert are both timer values, the only * way that can make sense is if the scan time is the number of @@ -526,30 +416,18 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER && cmd->scan_begin_arg != cmd->convert_arg * cmd->scan_end_arg) { - err++; + err |= -EINVAL; } - if (cmd->convert_src == TRIG_TIMER && cmd->convert_arg < MAX_SPEED) { - cmd->convert_arg = MAX_SPEED; - err++; - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, MAX_SPEED); - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg > 0x00ffffff) { - cmd->stop_arg = 0x00ffffff; - err++; - } - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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; @@ -557,19 +435,15 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - daqp_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + daqp_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - daqp_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; + arg = cmd->convert_arg; + daqp_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); } if (err) @@ -580,7 +454,7 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int counter; int scanlist_start_on_every_entry; @@ -589,10 +463,9 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) int i; int v; - if (local->stop) + if (devpriv->stop) return -EIO; - /* Stop any running conversion */ daqp_ai_cancel(dev, s); @@ -631,24 +504,10 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* Program scan list */ - for (i = 0; i < cmd->chanlist_len; i++) { + int start = (i == 0 || scanlist_start_on_every_entry); - int chanspec = cmd->chanlist[i]; - - /* Program one scan list entry */ - - v = DAQP_SCANLIST_CHANNEL(CR_CHAN(chanspec)) - | DAQP_SCANLIST_GAIN(CR_RANGE(chanspec)); - - if (CR_AREF(chanspec) == AREF_DIFF) - v |= DAQP_SCANLIST_DIFFERENTIAL; - - if (i == 0 || scanlist_start_on_every_entry) - v |= DAQP_SCANLIST_START; - - outb(v & 0xff, dev->iobase + DAQP_SCANLIST); - outb(v >> 8, dev->iobase + DAQP_SCANLIST); + daqp_ai_set_one_scanlist_entry(dev, cmd->chanlist[i], start); } /* Now it's time to program the FIFO threshold, basically the @@ -714,16 +573,16 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* Save away the number of conversions we should perform, and * compute the FIFO threshold (in bytes, not samples - that's - * why we multiple local->count by 2 = sizeof(sample)) + * why we multiple devpriv->count by 2 = sizeof(sample)) */ if (cmd->stop_src == TRIG_COUNT) { - local->count = cmd->stop_arg * cmd->scan_end_arg; - threshold = 2 * local->count; + devpriv->count = cmd->stop_arg * cmd->scan_end_arg; + threshold = 2 * devpriv->count; while (threshold > DAQP_FIFO_SIZE * 3 / 4) threshold /= 2; } else { - local->count = -1; + devpriv->count = -1; threshold = DAQP_FIFO_SIZE / 2; } @@ -757,16 +616,15 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) */ counter = 100; while (--counter - && (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) ; + && (inb(dev->iobase + DAQP_STATUS) & DAQP_STATUS_EVENTS)) + ; if (!counter) { - printk(KERN_ERR - "daqp: couldn't clear interrupts in status register\n"); + dev_err(dev->class_dev, + "couldn't clear interrupts in status register\n"); return -1; } - local->interrupt_mode = buffer; - local->dev = dev; - local->s = s; + devpriv->interrupt_mode = buffer; /* Start conversion */ outb(DAQP_COMMAND_ARM | DAQP_COMMAND_FIFO_DATA, @@ -775,349 +633,184 @@ static int daqp_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) return 0; } -/* Single-shot analog output routine */ - static int daqp_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 local_info_t *local = (struct local_info_t *)s->private; - int d; - unsigned int chan; + struct daqp_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int val; + int i; - if (local->stop) + if (devpriv->stop) return -EIO; - chan = CR_CHAN(insn->chanspec); - d = data[0]; - d &= 0x0fff; - d ^= 0x0800; /* Flip the sign */ - d |= chan << 12; - /* Make sure D/A update mode is direct update */ outb(0, dev->iobase + DAQP_AUX); - outw(d, dev->iobase + DAQP_DA); + for (i = 0; i > insn->n; i++) { + val = data[0]; + val &= 0x0fff; + val ^= 0x0800; /* Flip the sign */ + val |= (chan << 12); - return 1; -} + outw(val, dev->iobase + DAQP_DA); + } -/* Digital input routine */ + return insn->n; +} -static int daqp_di_insn_read(struct comedi_device *dev, +static int daqp_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct local_info_t *local = (struct local_info_t *)s->private; + struct daqp_private *devpriv = dev->private; - if (local->stop) + if (devpriv->stop) return -EIO; data[0] = inb(dev->iobase + DAQP_DIGITAL_IO); - return 1; -} - -/* Digital output routine */ - -static int daqp_do_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct local_info_t *local = (struct local_info_t *)s->private; - - if (local->stop) - return -EIO; - - outw(data[0] & 0xf, dev->iobase + DAQP_DIGITAL_IO); - - return 1; + return insn->n; } -/* daqp_attach is called via comedi_config to attach a comedi device - * to a /dev/comedi*. Note that this is different from daqp_cs_attach() - * which is called by the pcmcia subsystem to attach the PCMCIA card - * when it is inserted. - */ - -static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int daqp_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - int ret; - struct local_info_t *local = dev_table[it->options[0]]; - struct comedi_subdevice *s; + struct daqp_private *devpriv = dev->private; - if (it->options[0] < 0 || it->options[0] >= MAX_DEV || !local) { - printk("comedi%d: No such daqp device %d\n", - dev->minor, it->options[0]); + if (devpriv->stop) return -EIO; - } - - /* Typically brittle code that I don't completely understand, - * but "it works on my card". The intent is to pull the model - * number of the card out the PCMCIA CIS and stash it away as - * the COMEDI board_name. Looks like the third field in - * CISTPL_VERS_1 (offset 2) holds what we're looking for. If - * it doesn't work, who cares, just leave it as "DAQP". - */ - - strcpy(local->board_name, "DAQP"); - dev->board_name = local->board_name; - if (local->link->prod_id[2]) { - if (strncmp(local->link->prod_id[2], "DAQP", 4) == 0) { - strncpy(local->board_name, local->link->prod_id[2], - sizeof(local->board_name)); - } - } - - dev->iobase = local->link->resource[0]->start; - - ret = alloc_subdevices(dev, 4); - if (ret < 0) - return ret; - - printk(KERN_INFO "comedi%d: attaching daqp%d (io 0x%04lx)\n", - dev->minor, it->options[0], dev->iobase); - - s = dev->subdevices + 0; - dev->read_subdev = s; - s->private = local; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; - s->n_chan = 8; - s->len_chanlist = 2048; - s->maxdata = 0xffff; - s->range_table = &range_daqp_ai; - s->insn_read = daqp_ai_insn_read; - s->do_cmdtest = daqp_ai_cmdtest; - s->do_cmd = daqp_ai_cmd; - s->cancel = daqp_ai_cancel; - - s = dev->subdevices + 1; - dev->write_subdev = s; - s->private = local; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 2; - s->len_chanlist = 1; - s->maxdata = 0x0fff; - s->range_table = &range_daqp_ao; - s->insn_write = daqp_ao_insn_write; - - s = dev->subdevices + 2; - s->private = local; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 1; - s->len_chanlist = 1; - s->insn_read = daqp_di_insn_read; - - s = dev->subdevices + 3; - s->private = local; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 1; - s->len_chanlist = 1; - s->insn_write = daqp_do_insn_write; - - return 1; -} - -/* daqp_detach (called from comedi_comdig) does nothing. If the PCMCIA - * card is removed, daqp_cs_detach() is called by the pcmcia subsystem. - */ -static int daqp_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: detaching daqp\n", dev->minor); - - return 0; -} - -/*==================================================================== - - PCMCIA interface code - - The rest of the code in this file is based on dummy_cs.c v1.24 - from the Linux pcmcia_cs distribution v3.1.8 and is subject - to the following license agreement. - - The remaining contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - <dhinds@pcmcia.sourceforge.org>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -static void daqp_cs_config(struct pcmcia_device *link); -static void daqp_cs_release(struct pcmcia_device *link); -static int daqp_cs_suspend(struct pcmcia_device *p_dev); -static int daqp_cs_resume(struct pcmcia_device *p_dev); - -static int daqp_cs_attach(struct pcmcia_device *); -static void daqp_cs_detach(struct pcmcia_device *); - -static int daqp_cs_attach(struct pcmcia_device *link) -{ - struct local_info_t *local; - int i; - - dev_dbg(&link->dev, "daqp_cs_attach()\n"); - - for (i = 0; i < MAX_DEV; i++) - if (dev_table[i] == NULL) - break; - if (i == MAX_DEV) { - printk(KERN_NOTICE "daqp_cs: no devices available\n"); - return -ENODEV; - } - - /* Allocate space for private device-specific data */ - local = kzalloc(sizeof(struct local_info_t), GFP_KERNEL); - if (!local) - return -ENOMEM; + if (comedi_dio_update_state(s, data)) + outb(s->state, dev->iobase + DAQP_DIGITAL_IO); - local->table_index = i; - dev_table[i] = local; - local->link = link; - link->priv = local; + data[1] = s->state; - daqp_cs_config(link); - - return 0; -} /* daqp_cs_attach */ - -static void daqp_cs_detach(struct pcmcia_device *link) -{ - struct local_info_t *dev = link->priv; - - dev_dbg(&link->dev, "daqp_cs_detach\n"); - - dev->stop = 1; - daqp_cs_release(link); - - /* Unlink device structure, and free it */ - dev_table[dev->table_index] = NULL; - kfree(dev); - -} /* daqp_cs_detach */ - -static int daqp_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) -{ - if (p_dev->config_index == 0) - return -EINVAL; - - return pcmcia_request_io(p_dev); + return insn->n; } -static void daqp_cs_config(struct pcmcia_device *link) +static int daqp_auto_attach(struct comedi_device *dev, + unsigned long context) { + struct pcmcia_device *link = comedi_to_pcmcia_dev(dev); + struct daqp_private *devpriv; + struct comedi_subdevice *s; int ret; - dev_dbg(&link->dev, "daqp_cs_config\n"); - - link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = pcmcia_loop_config(link, daqp_pcmcia_config_loop, NULL); - if (ret) { - dev_warn(&link->dev, "no configuration found\n"); - goto failed; - } + link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ; + ret = comedi_pcmcia_enable(dev, NULL); + if (ret) + return ret; + dev->iobase = link->resource[0]->start; + link->priv = dev; ret = pcmcia_request_irq(link, daqp_interrupt); if (ret) - goto failed; + return ret; - ret = pcmcia_enable_device(link); + ret = comedi_alloc_subdevices(dev, 4); if (ret) - goto failed; - - return; - -failed: - daqp_cs_release(link); + return ret; -} /* daqp_cs_config */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ; + s->n_chan = 8; + s->len_chanlist = 2048; + s->maxdata = 0xffff; + s->range_table = &range_daqp_ai; + s->insn_read = daqp_ai_insn_read; + s->do_cmdtest = daqp_ai_cmdtest; + s->do_cmd = daqp_ai_cmd; + s->cancel = daqp_ai_cancel; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &range_bipolar5; + s->insn_write = daqp_ao_insn_write; + + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 1; + s->maxdata = 1; + s->insn_bits = daqp_di_insn_bits; + + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 1; + s->maxdata = 1; + s->insn_bits = daqp_do_insn_bits; -static void daqp_cs_release(struct pcmcia_device *link) -{ - dev_dbg(&link->dev, "daqp_cs_release\n"); + return 0; +} - pcmcia_disable_device(link); -} /* daqp_cs_release */ +static struct comedi_driver driver_daqp = { + .driver_name = "quatech_daqp_cs", + .module = THIS_MODULE, + .auto_attach = daqp_auto_attach, + .detach = comedi_pcmcia_disable, +}; static int daqp_cs_suspend(struct pcmcia_device *link) { - struct local_info_t *local = link->priv; + struct comedi_device *dev = link->priv; + struct daqp_private *devpriv = dev ? dev->private : NULL; /* Mark the device as stopped, to block IO until later */ - local->stop = 1; + if (devpriv) + devpriv->stop = 1; + return 0; } static int daqp_cs_resume(struct pcmcia_device *link) { - struct local_info_t *local = link->priv; + struct comedi_device *dev = link->priv; + struct daqp_private *devpriv = dev ? dev->private : NULL; - local->stop = 0; + if (devpriv) + devpriv->stop = 0; return 0; } -/*====================================================================*/ - -#ifdef MODULE +static int daqp_cs_attach(struct pcmcia_device *link) +{ + return comedi_pcmcia_auto_config(link, &driver_daqp); +} static const struct pcmcia_device_id daqp_cs_id_table[] = { PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0027), PCMCIA_DEVICE_NULL }; - MODULE_DEVICE_TABLE(pcmcia, daqp_cs_id_table); -MODULE_AUTHOR("Brent Baccala <baccala@freesoft.org>"); -MODULE_DESCRIPTION("Comedi driver for Quatech DAQP PCMCIA data capture cards"); -MODULE_LICENSE("GPL"); static struct pcmcia_driver daqp_cs_driver = { - .probe = daqp_cs_attach, - .remove = daqp_cs_detach, - .suspend = daqp_cs_suspend, - .resume = daqp_cs_resume, - .id_table = daqp_cs_id_table, - .owner = THIS_MODULE, - .name = "quatech_daqp_cs", + .name = "quatech_daqp_cs", + .owner = THIS_MODULE, + .id_table = daqp_cs_id_table, + .probe = daqp_cs_attach, + .remove = comedi_pcmcia_auto_unconfig, + .suspend = daqp_cs_suspend, + .resume = daqp_cs_resume, }; +module_comedi_pcmcia_driver(driver_daqp, daqp_cs_driver); -int __init init_module(void) -{ - pcmcia_register_driver(&daqp_cs_driver); - comedi_driver_register(&driver_daqp); - return 0; -} - -void __exit cleanup_module(void) -{ - comedi_driver_unregister(&driver_daqp); - pcmcia_unregister_driver(&daqp_cs_driver); -} - -#endif +MODULE_DESCRIPTION("Comedi driver for Quatech DAQP PCMCIA data capture cards"); +MODULE_AUTHOR("Brent Baccala <baccala@freesoft.org>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 7f09ed755fe..d55c5893203 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -1,119 +1,228 @@ /* - comedi/drivers/rtd520.c - Comedi driver for Real Time Devices (RTD) PCI4520/DM7520 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + * comedi/drivers/rtd520.c + * Comedi driver for Real Time Devices (RTD) PCI4520/DM7520 + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2001 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ -/* -Driver: rtd520 -Description: Real Time Devices PCI4520/DM7520 -Author: Dan Christian -Devices: [Real Time Devices] DM7520HR-1 (rtd520), DM7520HR-8, - PCI4520, PCI4520-8 -Status: Works. Only tested on DM7520-8. Not SMP safe. - -Configuration options: - [0] - PCI bus of device (optional) - If bus/slot is not specified, the first available PCI - device will be used. - [1] - PCI slot of device (optional) -*/ /* - Created by Dan Christian, NASA Ames Research Center. - - The PCI4520 is a PCI card. The DM7520 is a PC/104-plus card. - Both have: - 8/16 12 bit ADC with FIFO and channel gain table - 8 bits high speed digital out (for external MUX) (or 8 in or 8 out) - 8 bits high speed digital in with FIFO and interrupt on change (or 8 IO) - 2 12 bit DACs with FIFOs - 2 bits output - 2 bits input - bus mastering DMA - timers: ADC sample, pacer, burst, about, delay, DA1, DA2 - sample counter - 3 user timer/counters (8254) - external interrupt - - The DM7520 has slightly fewer features (fewer gain steps). - - These boards can support external multiplexors and multi-board - synchronization, but this driver doesn't support that. - - Board docs: http://www.rtdusa.com/PC104/DM/analog%20IO/dm7520.htm - Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf - Example source: http://www.rtdusa.com/examples/dm/dm7520.zip - Call them and ask for the register level manual. - PCI chip: http://www.plxtech.com/products/io/pci9080 - - Notes: - This board is memory mapped. There is some IO stuff, but it isn't needed. - - I use a pretty loose naming style within the driver (rtd_blah). - All externally visible names should be rtd520_blah. - I use camelCase for structures (and inside them). - I may also use upper CamelCase for function names (old habit). - - This board is somewhat related to the RTD PCI4400 board. - - I borrowed heavily from the ni_mio_common, ni_atmio16d, mite, and - das1800, since they have the best documented code. Driver - cb_pcidas64.c uses the same DMA controller. - - As far as I can tell, the About interrupt doesn't work if Sample is - also enabled. It turns out that About really isn't needed, since - we always count down samples read. - - There was some timer/counter code, but it didn't follow the right API. - -*/ + * Driver: rtd520 + * Description: Real Time Devices PCI4520/DM7520 + * Devices: (Real Time Devices) DM7520HR-1 [DM7520] + * (Real Time Devices) DM7520HR-8 [DM7520] + * (Real Time Devices) PCI4520 [PCI4520] + * (Real Time Devices) PCI4520-8 [PCI4520] + * Author: Dan Christian + * Status: Works. Only tested on DM7520-8. Not SMP safe. + * + * Configuration options: not applicable, uses PCI auto config + */ /* - driver status: - - Analog-In supports instruction and command mode. - - With DMA, you can sample at 1.15Mhz with 70% idle on a 400Mhz K6-2 - (single channel, 64K read buffer). I get random system lockups when - using DMA with ALI-15xx based systems. I haven't been able to test - any other chipsets. The lockups happen soon after the start of an - acquistion, not in the middle of a long run. - - Without DMA, you can do 620Khz sampling with 20% idle on a 400Mhz K6-2 - (with a 256K read buffer). - - Digital-IO and Analog-Out only support instruction mode. + * Created by Dan Christian, NASA Ames Research Center. + * + * The PCI4520 is a PCI card. The DM7520 is a PC/104-plus card. + * Both have: + * 8/16 12 bit ADC with FIFO and channel gain table + * 8 bits high speed digital out (for external MUX) (or 8 in or 8 out) + * 8 bits high speed digital in with FIFO and interrupt on change (or 8 IO) + * 2 12 bit DACs with FIFOs + * 2 bits output + * 2 bits input + * bus mastering DMA + * timers: ADC sample, pacer, burst, about, delay, DA1, DA2 + * sample counter + * 3 user timer/counters (8254) + * external interrupt + * + * The DM7520 has slightly fewer features (fewer gain steps). + * + * These boards can support external multiplexors and multi-board + * synchronization, but this driver doesn't support that. + * + * Board docs: http://www.rtdusa.com/PC104/DM/analog%20IO/dm7520.htm + * Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf + * Example source: http://www.rtdusa.com/examples/dm/dm7520.zip + * Call them and ask for the register level manual. + * PCI chip: http://www.plxtech.com/products/io/pci9080 + * + * Notes: + * This board is memory mapped. There is some IO stuff, but it isn't needed. + * + * I use a pretty loose naming style within the driver (rtd_blah). + * All externally visible names should be rtd520_blah. + * I use camelCase for structures (and inside them). + * I may also use upper CamelCase for function names (old habit). + * + * This board is somewhat related to the RTD PCI4400 board. + * + * I borrowed heavily from the ni_mio_common, ni_atmio16d, mite, and + * das1800, since they have the best documented code. Driver cb_pcidas64.c + * uses the same DMA controller. + * + * As far as I can tell, the About interrupt doesn't work if Sample is + * also enabled. It turns out that About really isn't needed, since + * we always count down samples read. + * + * There was some timer/counter code, but it didn't follow the right API. + */ -*/ +/* + * driver status: + * + * Analog-In supports instruction and command mode. + * + * With DMA, you can sample at 1.15Mhz with 70% idle on a 400Mhz K6-2 + * (single channel, 64K read buffer). I get random system lockups when + * using DMA with ALI-15xx based systems. I haven't been able to test + * any other chipsets. The lockups happen soon after the start of an + * acquistion, not in the middle of a long run. + * + * Without DMA, you can do 620Khz sampling with 20% idle on a 400Mhz K6-2 + * (with a 256K read buffer). + * + * Digital-IO and Analog-Out only support instruction mode. + */ -#include <linux/interrupt.h> +#include <linux/module.h> +#include <linux/pci.h> #include <linux/delay.h> +#include <linux/interrupt.h> #include "../comedidev.h" -#include "comedi_pci.h" -#define DRV_NAME "rtd520" +#include "comedi_fc.h" +#include "plx9080.h" + +/* + * Local Address Space 0 Offsets + */ +#define LAS0_USER_IO 0x0008 /* User I/O */ +#define LAS0_ADC 0x0010 /* FIFO Status/Software A/D Start */ +#define FS_DAC1_NOT_EMPTY (1 << 0) /* DAC1 FIFO not empty */ +#define FS_DAC1_HEMPTY (1 << 1) /* DAC1 FIFO half empty */ +#define FS_DAC1_NOT_FULL (1 << 2) /* DAC1 FIFO not full */ +#define FS_DAC2_NOT_EMPTY (1 << 4) /* DAC2 FIFO not empty */ +#define FS_DAC2_HEMPTY (1 << 5) /* DAC2 FIFO half empty */ +#define FS_DAC2_NOT_FULL (1 << 6) /* DAC2 FIFO not full */ +#define FS_ADC_NOT_EMPTY (1 << 8) /* ADC FIFO not empty */ +#define FS_ADC_HEMPTY (1 << 9) /* ADC FIFO half empty */ +#define FS_ADC_NOT_FULL (1 << 10) /* ADC FIFO not full */ +#define FS_DIN_NOT_EMPTY (1 << 12) /* DIN FIFO not empty */ +#define FS_DIN_HEMPTY (1 << 13) /* DIN FIFO half empty */ +#define FS_DIN_NOT_FULL (1 << 14) /* DIN FIFO not full */ +#define LAS0_DAC1 0x0014 /* Software D/A1 Update (w) */ +#define LAS0_DAC2 0x0018 /* Software D/A2 Update (w) */ +#define LAS0_DAC 0x0024 /* Software Simultaneous Update (w) */ +#define LAS0_PACER 0x0028 /* Software Pacer Start/Stop */ +#define LAS0_TIMER 0x002c /* Timer Status/HDIN Software Trig. */ +#define LAS0_IT 0x0030 /* Interrupt Status/Enable */ +#define IRQM_ADC_FIFO_WRITE (1 << 0) /* ADC FIFO Write */ +#define IRQM_CGT_RESET (1 << 1) /* Reset CGT */ +#define IRQM_CGT_PAUSE (1 << 3) /* Pause CGT */ +#define IRQM_ADC_ABOUT_CNT (1 << 4) /* About Counter out */ +#define IRQM_ADC_DELAY_CNT (1 << 5) /* Delay Counter out */ +#define IRQM_ADC_SAMPLE_CNT (1 << 6) /* ADC Sample Counter */ +#define IRQM_DAC1_UCNT (1 << 7) /* DAC1 Update Counter */ +#define IRQM_DAC2_UCNT (1 << 8) /* DAC2 Update Counter */ +#define IRQM_UTC1 (1 << 9) /* User TC1 out */ +#define IRQM_UTC1_INV (1 << 10) /* User TC1 out, inverted */ +#define IRQM_UTC2 (1 << 11) /* User TC2 out */ +#define IRQM_DIGITAL_IT (1 << 12) /* Digital Interrupt */ +#define IRQM_EXTERNAL_IT (1 << 13) /* External Interrupt */ +#define IRQM_ETRIG_RISING (1 << 14) /* Ext Trigger rising-edge */ +#define IRQM_ETRIG_FALLING (1 << 15) /* Ext Trigger falling-edge */ +#define LAS0_CLEAR 0x0034 /* Clear/Set Interrupt Clear Mask */ +#define LAS0_OVERRUN 0x0038 /* Pending interrupts/Clear Overrun */ +#define LAS0_PCLK 0x0040 /* Pacer Clock (24bit) */ +#define LAS0_BCLK 0x0044 /* Burst Clock (10bit) */ +#define LAS0_ADC_SCNT 0x0048 /* A/D Sample counter (10bit) */ +#define LAS0_DAC1_UCNT 0x004c /* D/A1 Update counter (10 bit) */ +#define LAS0_DAC2_UCNT 0x0050 /* D/A2 Update counter (10 bit) */ +#define LAS0_DCNT 0x0054 /* Delay counter (16 bit) */ +#define LAS0_ACNT 0x0058 /* About counter (16 bit) */ +#define LAS0_DAC_CLK 0x005c /* DAC clock (16bit) */ +#define LAS0_UTC0 0x0060 /* 8254 TC Counter 0 */ +#define LAS0_UTC1 0x0064 /* 8254 TC Counter 1 */ +#define LAS0_UTC2 0x0068 /* 8254 TC Counter 2 */ +#define LAS0_UTC_CTRL 0x006c /* 8254 TC Control */ +#define LAS0_DIO0 0x0070 /* Digital I/O Port 0 */ +#define LAS0_DIO1 0x0074 /* Digital I/O Port 1 */ +#define LAS0_DIO0_CTRL 0x0078 /* Digital I/O Control */ +#define LAS0_DIO_STATUS 0x007c /* Digital I/O Status */ +#define LAS0_BOARD_RESET 0x0100 /* Board reset */ +#define LAS0_DMA0_SRC 0x0104 /* DMA 0 Sources select */ +#define LAS0_DMA1_SRC 0x0108 /* DMA 1 Sources select */ +#define LAS0_ADC_CONVERSION 0x010c /* A/D Conversion Signal select */ +#define LAS0_BURST_START 0x0110 /* Burst Clock Start Trigger select */ +#define LAS0_PACER_START 0x0114 /* Pacer Clock Start Trigger select */ +#define LAS0_PACER_STOP 0x0118 /* Pacer Clock Stop Trigger select */ +#define LAS0_ACNT_STOP_ENABLE 0x011c /* About Counter Stop Enable */ +#define LAS0_PACER_REPEAT 0x0120 /* Pacer Start Trigger Mode select */ +#define LAS0_DIN_START 0x0124 /* HiSpd DI Sampling Signal select */ +#define LAS0_DIN_FIFO_CLEAR 0x0128 /* Digital Input FIFO Clear */ +#define LAS0_ADC_FIFO_CLEAR 0x012c /* A/D FIFO Clear */ +#define LAS0_CGT_WRITE 0x0130 /* Channel Gain Table Write */ +#define LAS0_CGL_WRITE 0x0134 /* Channel Gain Latch Write */ +#define LAS0_CG_DATA 0x0138 /* Digital Table Write */ +#define LAS0_CGT_ENABLE 0x013c /* Channel Gain Table Enable */ +#define LAS0_CG_ENABLE 0x0140 /* Digital Table Enable */ +#define LAS0_CGT_PAUSE 0x0144 /* Table Pause Enable */ +#define LAS0_CGT_RESET 0x0148 /* Reset Channel Gain Table */ +#define LAS0_CGT_CLEAR 0x014c /* Clear Channel Gain Table */ +#define LAS0_DAC1_CTRL 0x0150 /* D/A1 output type/range */ +#define LAS0_DAC1_SRC 0x0154 /* D/A1 update source */ +#define LAS0_DAC1_CYCLE 0x0158 /* D/A1 cycle mode */ +#define LAS0_DAC1_RESET 0x015c /* D/A1 FIFO reset */ +#define LAS0_DAC1_FIFO_CLEAR 0x0160 /* D/A1 FIFO clear */ +#define LAS0_DAC2_CTRL 0x0164 /* D/A2 output type/range */ +#define LAS0_DAC2_SRC 0x0168 /* D/A2 update source */ +#define LAS0_DAC2_CYCLE 0x016c /* D/A2 cycle mode */ +#define LAS0_DAC2_RESET 0x0170 /* D/A2 FIFO reset */ +#define LAS0_DAC2_FIFO_CLEAR 0x0174 /* D/A2 FIFO clear */ +#define LAS0_ADC_SCNT_SRC 0x0178 /* A/D Sample Counter Source select */ +#define LAS0_PACER_SELECT 0x0180 /* Pacer Clock select */ +#define LAS0_SBUS0_SRC 0x0184 /* SyncBus 0 Source select */ +#define LAS0_SBUS0_ENABLE 0x0188 /* SyncBus 0 enable */ +#define LAS0_SBUS1_SRC 0x018c /* SyncBus 1 Source select */ +#define LAS0_SBUS1_ENABLE 0x0190 /* SyncBus 1 enable */ +#define LAS0_SBUS2_SRC 0x0198 /* SyncBus 2 Source select */ +#define LAS0_SBUS2_ENABLE 0x019c /* SyncBus 2 enable */ +#define LAS0_ETRG_POLARITY 0x01a4 /* Ext. Trigger polarity select */ +#define LAS0_EINT_POLARITY 0x01a8 /* Ext. Interrupt polarity select */ +#define LAS0_UTC0_CLOCK 0x01ac /* UTC0 Clock select */ +#define LAS0_UTC0_GATE 0x01b0 /* UTC0 Gate select */ +#define LAS0_UTC1_CLOCK 0x01b4 /* UTC1 Clock select */ +#define LAS0_UTC1_GATE 0x01b8 /* UTC1 Gate select */ +#define LAS0_UTC2_CLOCK 0x01bc /* UTC2 Clock select */ +#define LAS0_UTC2_GATE 0x01c0 /* UTC2 Gate select */ +#define LAS0_UOUT0_SELECT 0x01c4 /* User Output 0 source select */ +#define LAS0_UOUT1_SELECT 0x01c8 /* User Output 1 source select */ +#define LAS0_DMA0_RESET 0x01cc /* DMA0 Request state machine reset */ +#define LAS0_DMA1_RESET 0x01d0 /* DMA1 Request state machine reset */ + +/* + * Local Address Space 1 Offsets + */ +#define LAS1_ADC_FIFO 0x0000 /* A/D FIFO (16bit) */ +#define LAS1_HDIO_FIFO 0x0004 /* HiSpd DI FIFO (16bit) */ +#define LAS1_DAC1_FIFO 0x0008 /* D/A1 FIFO (16bit) */ +#define LAS1_DAC2_FIFO 0x000c /* D/A2 FIFO (16bit) */ /*====================================================================== Driver specific stuff (tunable) ======================================================================*/ -/* Enable this to test the new DMA support. You may get hard lock ups */ -/*#define USE_DMA*/ /* We really only need 2 buffers. More than that means being much smarter about knowing which ones are full. */ @@ -128,38 +237,10 @@ Configuration options: /* The board support a channel list up to the FIFO length (1K or 8K) */ #define RTD_MAX_CHANLIST 128 /* max channel list that we allow */ -/* tuning for ai/ao instruction done polling */ -#ifdef FAST_SPIN -#define WAIT_QUIETLY /* as nothing, spin on done bit */ -#define RTD_ADC_TIMEOUT 66000 /* 2 msec at 33mhz bus rate */ -#define RTD_DAC_TIMEOUT 66000 -#define RTD_DMA_TIMEOUT 33000 /* 1 msec */ -#else -/* by delaying, power and electrical noise are reduced somewhat */ -#define WAIT_QUIETLY udelay(1) -#define RTD_ADC_TIMEOUT 2000 /* in usec */ -#define RTD_DAC_TIMEOUT 2000 /* in usec */ -#define RTD_DMA_TIMEOUT 1000 /* in usec */ -#endif - /*====================================================================== Board specific stuff ======================================================================*/ -/* registers */ -#define PCI_VENDOR_ID_RTD 0x1435 -/* - The board has three memory windows: las0, las1, and lcfg (the PCI chip) - Las1 has the data and can be burst DMAed 32bits at a time. -*/ -#define LCFG_PCIINDEX 0 -/* PCI region 1 is a 256 byte IO space mapping. Use??? */ -#define LAS0_PCIINDEX 2 /* PCI memory resources */ -#define LAS1_PCIINDEX 3 -#define LCFG_PCISIZE 0x100 -#define LAS0_PCISIZE 0x200 -#define LAS1_PCISIZE 0x10 - #define RTD_CLOCK_RATE 8000000 /* 8Mhz onboard clock */ #define RTD_CLOCK_BASE 125 /* clock period in ns */ @@ -172,9 +253,6 @@ Configuration options: /* min speed when only 1 channel (no burst counter) */ #define RTD_MIN_SPEED_1 5000000 /* 200Hz, in nanoseconds */ -#include "rtd520.h" -#include "plx9080.h" - /* Setup continuous ring of 1/2 FIFO transfers. See RTD manual p91 */ #define DMA_MODE_BITS (\ PLX_LOCAL_BUS_16_WIDE_BITS \ @@ -186,7 +264,7 @@ Configuration options: | PLX_DEMAND_MODE_BIT) #define DMA_TRANSFER_BITS (\ -/* descriptors in PCI memory*/ PLX_DESC_IN_PCI_BIT \ +/* descriptors in PCI memory*/ PLX_DESC_IN_PCI_BIT \ /* interrupt at end of block */ | PLX_INTR_TERM_COUNT \ /* from board to PCI */ | PLX_XFER_LOCAL_TO_PCI) @@ -195,200 +273,116 @@ Configuration options: ======================================================================*/ /* - The board has 3 input modes and the gains of 1,2,4,...32 (, 64, 128) -*/ -static const struct comedi_lrange rtd_ai_7520_range = { 18, { - /* +-5V input range gain steps */ - BIP_RANGE(5.0), - BIP_RANGE(5.0 / 2), - BIP_RANGE(5.0 / 4), - BIP_RANGE(5.0 / 8), - BIP_RANGE(5.0 / - 16), - BIP_RANGE(5.0 / - 32), - /* +-10V input range gain steps */ - BIP_RANGE(10.0), - BIP_RANGE(10.0 / - 2), - BIP_RANGE(10.0 / - 4), - BIP_RANGE(10.0 / - 8), - BIP_RANGE(10.0 / - 16), - BIP_RANGE(10.0 / - 32), - /* +10V input range gain steps */ - UNI_RANGE(10.0), - UNI_RANGE(10.0 / - 2), - UNI_RANGE(10.0 / - 4), - UNI_RANGE(10.0 / - 8), - UNI_RANGE(10.0 / - 16), - UNI_RANGE(10.0 / - 32), - - } + * The board has 3 input modes and the gains of 1,2,4,...32 (, 64, 128) + */ +static const struct comedi_lrange rtd_ai_7520_range = { + 18, { + /* +-5V input range gain steps */ + BIP_RANGE(5.0), + BIP_RANGE(5.0 / 2), + BIP_RANGE(5.0 / 4), + BIP_RANGE(5.0 / 8), + BIP_RANGE(5.0 / 16), + BIP_RANGE(5.0 / 32), + /* +-10V input range gain steps */ + BIP_RANGE(10.0), + BIP_RANGE(10.0 / 2), + BIP_RANGE(10.0 / 4), + BIP_RANGE(10.0 / 8), + BIP_RANGE(10.0 / 16), + BIP_RANGE(10.0 / 32), + /* +10V input range gain steps */ + UNI_RANGE(10.0), + UNI_RANGE(10.0 / 2), + UNI_RANGE(10.0 / 4), + UNI_RANGE(10.0 / 8), + UNI_RANGE(10.0 / 16), + UNI_RANGE(10.0 / 32), + } }; /* PCI4520 has two more gains (6 more entries) */ -static const struct comedi_lrange rtd_ai_4520_range = { 24, { - /* +-5V input range gain steps */ - BIP_RANGE(5.0), - BIP_RANGE(5.0 / 2), - BIP_RANGE(5.0 / 4), - BIP_RANGE(5.0 / 8), - BIP_RANGE(5.0 / - 16), - BIP_RANGE(5.0 / - 32), - BIP_RANGE(5.0 / - 64), - BIP_RANGE(5.0 / - 128), - /* +-10V input range gain steps */ - BIP_RANGE(10.0), - BIP_RANGE(10.0 / - 2), - BIP_RANGE(10.0 / - 4), - BIP_RANGE(10.0 / - 8), - BIP_RANGE(10.0 / - 16), - BIP_RANGE(10.0 / - 32), - BIP_RANGE(10.0 / - 64), - BIP_RANGE(10.0 / - 128), - /* +10V input range gain steps */ - UNI_RANGE(10.0), - UNI_RANGE(10.0 / - 2), - UNI_RANGE(10.0 / - 4), - UNI_RANGE(10.0 / - 8), - UNI_RANGE(10.0 / - 16), - UNI_RANGE(10.0 / - 32), - UNI_RANGE(10.0 / - 64), - UNI_RANGE(10.0 / - 128), - } +static const struct comedi_lrange rtd_ai_4520_range = { + 24, { + /* +-5V input range gain steps */ + BIP_RANGE(5.0), + BIP_RANGE(5.0 / 2), + BIP_RANGE(5.0 / 4), + BIP_RANGE(5.0 / 8), + BIP_RANGE(5.0 / 16), + BIP_RANGE(5.0 / 32), + BIP_RANGE(5.0 / 64), + BIP_RANGE(5.0 / 128), + /* +-10V input range gain steps */ + BIP_RANGE(10.0), + BIP_RANGE(10.0 / 2), + BIP_RANGE(10.0 / 4), + BIP_RANGE(10.0 / 8), + BIP_RANGE(10.0 / 16), + BIP_RANGE(10.0 / 32), + BIP_RANGE(10.0 / 64), + BIP_RANGE(10.0 / 128), + /* +10V input range gain steps */ + UNI_RANGE(10.0), + UNI_RANGE(10.0 / 2), + UNI_RANGE(10.0 / 4), + UNI_RANGE(10.0 / 8), + UNI_RANGE(10.0 / 16), + UNI_RANGE(10.0 / 32), + UNI_RANGE(10.0 / 64), + UNI_RANGE(10.0 / 128), + } }; /* Table order matches range values */ -static const struct comedi_lrange rtd_ao_range = { 4, { - RANGE(0, 5), - RANGE(0, 10), - RANGE(-5, 5), - RANGE(-10, 10), - } +static const struct comedi_lrange rtd_ao_range = { + 4, { + UNI_RANGE(5), + UNI_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(10), + } }; -/* - Board descriptions - */ -struct rtdBoard { - const char *name; /* must be first */ - int device_id; - int aiChans; - int aiBits; - int aiMaxGain; - int range10Start; /* start of +-10V range */ - int rangeUniStart; /* start of +10V range */ +enum rtd_boardid { + BOARD_DM7520, + BOARD_PCI4520, }; -static const struct rtdBoard rtd520Boards[] = { - { - .name = "DM7520", - .device_id = 0x7520, - .aiChans = 16, - .aiBits = 12, - .aiMaxGain = 32, - .range10Start = 6, - .rangeUniStart = 12, - }, - { - .name = "PCI4520", - .device_id = 0x4520, - .aiChans = 16, - .aiBits = 12, - .aiMaxGain = 128, - .range10Start = 8, - .rangeUniStart = 16, - }, +struct rtd_boardinfo { + const char *name; + int range_bip10; /* start of +-10V range */ + int range_uni10; /* start of +10V range */ + const struct comedi_lrange *ai_range; }; -static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x7520) }, - { PCI_DEVICE(PCI_VENDOR_ID_RTD, 0x4520) }, - { 0 } +static const struct rtd_boardinfo rtd520Boards[] = { + [BOARD_DM7520] = { + .name = "DM7520", + .range_bip10 = 6, + .range_uni10 = 12, + .ai_range = &rtd_ai_7520_range, + }, + [BOARD_PCI4520] = { + .name = "PCI4520", + .range_bip10 = 8, + .range_uni10 = 16, + .ai_range = &rtd_ai_4520_range, + }, }; -MODULE_DEVICE_TABLE(pci, rtd520_pci_table); - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct rtdBoard *)dev->board_ptr) - -/* - This structure is for data unique to this hardware driver. - This is also unique for each board in the system. -*/ -struct rtdPrivate { +struct rtd_private { /* memory mapped board structures */ - void *las0; - void *las1; - void *lcfg; + void __iomem *las0; + void __iomem *las1; + void __iomem *lcfg; - unsigned long intCount; /* interrupt count */ - long aiCount; /* total transfer size (samples) */ - int transCount; /* # to tranfer data. 0->1/2FIFO */ + long ai_count; /* total transfer size (samples) */ + int xfer_count; /* # to transfer data. 0->1/2FIFO */ int flags; /* flag event modes */ - - /* PCI device info */ - struct pci_dev *pci_dev; - int got_regions; /* non-zero if PCI regions owned */ - - /* channel list info */ - /* chanBipolar tracks whether a channel is bipolar (and needs +2048) */ - unsigned char chanBipolar[RTD_MAX_CHANLIST / 8]; /* bit array */ - - /* read back data */ - unsigned int aoValue[2]; /* Used for AO read back */ - - /* timer gate (when enabled) */ - u8 utcGate[4]; /* 1 extra allows simple range check */ - - /* shadow registers affect other registers, but can't be read back */ - /* The macros below update these on writes */ - u16 intMask; /* interrupt mask */ - u16 intClearMask; /* interrupt clear mask */ - u8 utcCtrl[4]; /* crtl mode for 3 utc + read back */ - u8 dioStatus; /* could be read back (dio0Ctrl) */ -#ifdef USE_DMA - /* Always DMA 1/2 FIFO. Buffer (dmaBuff?) is (at least) twice that size. - After transferring, interrupt processes 1/2 FIFO and passes to comedi */ - s16 dma0Offset; /* current processing offset (0, 1/2) */ - uint16_t *dma0Buff[DMA_CHAIN_COUNT]; /* DMA buffers (for ADC) */ - dma_addr_t dma0BuffPhysAddr[DMA_CHAIN_COUNT]; /* physical addresses */ - struct plx_dma_desc *dma0Chain; /* DMA descriptor ring for dmaBuff */ - dma_addr_t dma0ChainPhysAddr; /* physical addresses */ - /* shadow registers */ - u8 dma0Control; - u8 dma1Control; -#endif /* USE_DMA */ - unsigned fifoLen; + DECLARE_BITMAP(chan_is_bipolar, RTD_MAX_CHANLIST); + unsigned int ao_readback[2]; + unsigned fifosz; }; /* bit defines for "flags" */ @@ -396,818 +390,80 @@ struct rtdPrivate { #define DMA0_ACTIVE 0x02 /* DMA0 is active */ #define DMA1_ACTIVE 0x04 /* DMA1 is active */ -/* Macros for accessing channel list bit array */ -#define CHAN_ARRAY_TEST(array, index) \ - (((array)[(index)/8] >> ((index) & 0x7)) & 0x1) -#define CHAN_ARRAY_SET(array, index) \ - (((array)[(index)/8] |= 1 << ((index) & 0x7))) -#define CHAN_ARRAY_CLEAR(array, index) \ - (((array)[(index)/8] &= ~(1 << ((index) & 0x7)))) - -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct rtdPrivate *)dev->private) - -/* Macros to access registers */ - -/* Reset board */ -#define RtdResetBoard(dev) \ - writel(0, devpriv->las0+LAS0_BOARD_RESET) - -/* Reset channel gain table read pointer */ -#define RtdResetCGT(dev) \ - writel(0, devpriv->las0+LAS0_CGT_RESET) - -/* Reset channel gain table read and write pointers */ -#define RtdClearCGT(dev) \ - writel(0, devpriv->las0+LAS0_CGT_CLEAR) - -/* Reset channel gain table read and write pointers */ -#define RtdEnableCGT(dev, v) \ - writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_CGT_ENABLE) - -/* Write channel gain table entry */ -#define RtdWriteCGTable(dev, v) \ - writel(v, devpriv->las0+LAS0_CGT_WRITE) - -/* Write Channel Gain Latch */ -#define RtdWriteCGLatch(dev, v) \ - writel(v, devpriv->las0+LAS0_CGL_WRITE) - -/* Reset ADC FIFO */ -#define RtdAdcClearFifo(dev) \ - writel(0, devpriv->las0+LAS0_ADC_FIFO_CLEAR) - -/* Set ADC start conversion source select (write only) */ -#define RtdAdcConversionSource(dev, v) \ - writel(v, devpriv->las0+LAS0_ADC_CONVERSION) - -/* Set burst start source select (write only) */ -#define RtdBurstStartSource(dev, v) \ - writel(v, devpriv->las0+LAS0_BURST_START) - -/* Set Pacer start source select (write only) */ -#define RtdPacerStartSource(dev, v) \ - writel(v, devpriv->las0+LAS0_PACER_START) - -/* Set Pacer stop source select (write only) */ -#define RtdPacerStopSource(dev, v) \ - writel(v, devpriv->las0+LAS0_PACER_STOP) - -/* Set Pacer clock source select (write only) 0=external 1=internal */ -#define RtdPacerClockSource(dev, v) \ - writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_PACER_SELECT) - -/* Set sample counter source select (write only) */ -#define RtdAdcSampleCounterSource(dev, v) \ - writel(v, devpriv->las0+LAS0_ADC_SCNT_SRC) - -/* Set Pacer trigger mode select (write only) 0=single cycle, 1=repeat */ -#define RtdPacerTriggerMode(dev, v) \ - writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_PACER_REPEAT) - -/* Set About counter stop enable (write only) */ -#define RtdAboutStopEnable(dev, v) \ - writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_ACNT_STOP_ENABLE) - -/* Set external trigger polarity (write only) 0=positive edge, 1=negative */ -#define RtdTriggerPolarity(dev, v) \ - writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_ETRG_POLARITY) - -/* Start single ADC conversion */ -#define RtdAdcStart(dev) \ - writew(0, devpriv->las0+LAS0_ADC) - -/* Read one ADC data value (12bit (with sign extend) as 16bit) */ -/* Note: matches what DMA would get. Actual value >> 3 */ -#define RtdAdcFifoGet(dev) \ - readw(devpriv->las1+LAS1_ADC_FIFO) - -/* Read two ADC data values (DOESN'T WORK) */ -#define RtdAdcFifoGet2(dev) \ - readl(devpriv->las1+LAS1_ADC_FIFO) - -/* FIFO status */ -#define RtdFifoStatus(dev) \ - readl(devpriv->las0+LAS0_ADC) - -/* pacer start/stop read=start, write=stop*/ -#define RtdPacerStart(dev) \ - readl(devpriv->las0+LAS0_PACER) -#define RtdPacerStop(dev) \ - writel(0, devpriv->las0+LAS0_PACER) - -/* Interrupt status */ -#define RtdInterruptStatus(dev) \ - readw(devpriv->las0+LAS0_IT) - -/* Interrupt mask */ -#define RtdInterruptMask(dev, v) \ - writew((devpriv->intMask = (v)), devpriv->las0+LAS0_IT) - -/* Interrupt status clear (only bits set in mask) */ -#define RtdInterruptClear(dev) \ - readw(devpriv->las0+LAS0_CLEAR) - -/* Interrupt clear mask */ -#define RtdInterruptClearMask(dev, v) \ - writew((devpriv->intClearMask = (v)), devpriv->las0+LAS0_CLEAR) - -/* Interrupt overrun status */ -#define RtdInterruptOverrunStatus(dev) \ - readl(devpriv->las0+LAS0_OVERRUN) - -/* Interrupt overrun clear */ -#define RtdInterruptOverrunClear(dev) \ - writel(0, devpriv->las0+LAS0_OVERRUN) - -/* Pacer counter, 24bit */ -#define RtdPacerCount(dev) \ - readl(devpriv->las0+LAS0_PCLK) -#define RtdPacerCounter(dev, v) \ - writel((v) & 0xffffff, devpriv->las0+LAS0_PCLK) - -/* Burst counter, 10bit */ -#define RtdBurstCount(dev) \ - readl(devpriv->las0+LAS0_BCLK) -#define RtdBurstCounter(dev, v) \ - writel((v) & 0x3ff, devpriv->las0+LAS0_BCLK) - -/* Delay counter, 16bit */ -#define RtdDelayCount(dev) \ - readl(devpriv->las0+LAS0_DCLK) -#define RtdDelayCounter(dev, v) \ - writel((v) & 0xffff, devpriv->las0+LAS0_DCLK) - -/* About counter, 16bit */ -#define RtdAboutCount(dev) \ - readl(devpriv->las0+LAS0_ACNT) -#define RtdAboutCounter(dev, v) \ - writel((v) & 0xffff, devpriv->las0+LAS0_ACNT) - -/* ADC sample counter, 10bit */ -#define RtdAdcSampleCount(dev) \ - readl(devpriv->las0+LAS0_ADC_SCNT) -#define RtdAdcSampleCounter(dev, v) \ - writel((v) & 0x3ff, devpriv->las0+LAS0_ADC_SCNT) - -/* User Timer/Counter (8254) */ -#define RtdUtcCounterGet(dev, n) \ - readb(devpriv->las0 \ - + ((n <= 0) ? LAS0_UTC0 : ((1 == n) ? LAS0_UTC1 : LAS0_UTC2))) - -#define RtdUtcCounterPut(dev, n, v) \ - writeb((v) & 0xff, devpriv->las0 \ - + ((n <= 0) ? LAS0_UTC0 : ((1 == n) ? LAS0_UTC1 : LAS0_UTC2))) - -/* Set UTC (8254) control byte */ -#define RtdUtcCtrlPut(dev, n, v) \ - writeb(devpriv->utcCtrl[(n) & 3] = (((n) & 3) << 6) | ((v) & 0x3f), \ - devpriv->las0 + LAS0_UTC_CTRL) - -/* Set UTCn clock source (write only) */ -#define RtdUtcClockSource(dev, n, v) \ - writew(v, devpriv->las0 \ - + ((n <= 0) ? LAS0_UTC0_CLOCK : \ - ((1 == n) ? LAS0_UTC1_CLOCK : LAS0_UTC2_CLOCK))) - -/* Set UTCn gate source (write only) */ -#define RtdUtcGateSource(dev, n, v) \ - writew(v, devpriv->las0 \ - + ((n <= 0) ? LAS0_UTC0_GATE : \ - ((1 == n) ? LAS0_UTC1_GATE : LAS0_UTC2_GATE))) - -/* User output N source select (write only) */ -#define RtdUsrOutSource(dev, n, v) \ - writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : LAS0_UOUT1_SELECT)) - -/* Digital IO */ -#define RtdDio0Read(dev) \ - (readw(devpriv->las0+LAS0_DIO0) & 0xff) -#define RtdDio0Write(dev, v) \ - writew((v) & 0xff, devpriv->las0+LAS0_DIO0) - -#define RtdDio1Read(dev) \ - (readw(devpriv->las0+LAS0_DIO1) & 0xff) -#define RtdDio1Write(dev, v) \ - writew((v) & 0xff, devpriv->las0+LAS0_DIO1) - -#define RtdDioStatusRead(dev) \ - (readw(devpriv->las0+LAS0_DIO_STATUS) & 0xff) -#define RtdDioStatusWrite(dev, v) \ - writew((devpriv->dioStatus = (v)), devpriv->las0+LAS0_DIO_STATUS) - -#define RtdDio0CtrlRead(dev) \ - (readw(devpriv->las0+LAS0_DIO0_CTRL) & 0xff) -#define RtdDio0CtrlWrite(dev, v) \ - writew((v) & 0xff, devpriv->las0+LAS0_DIO0_CTRL) - -/* Digital to Analog converter */ -/* Write one data value (sign + 12bit + marker bits) */ -/* Note: matches what DMA would put. Actual value << 3 */ -#define RtdDacFifoPut(dev, n, v) \ - writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO)) - -/* Start single DAC conversion */ -#define RtdDacUpdate(dev, n) \ - writew(0, devpriv->las0 + (((n) == 0) ? LAS0_DAC1 : LAS0_DAC2)) - -/* Start single DAC conversion on both DACs */ -#define RtdDacBothUpdate(dev) \ - writew(0, devpriv->las0+LAS0_DAC) - -/* Set DAC output type and range */ -#define RtdDacRange(dev, n, v) \ - writew((v) & 7, devpriv->las0 \ - +(((n) == 0) ? LAS0_DAC1_CTRL : LAS0_DAC2_CTRL)) - -/* Reset DAC FIFO */ -#define RtdDacClearFifo(dev, n) \ - writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : LAS0_DAC2_RESET)) - -/* Set source for DMA 0 (write only, shadow?) */ -#define RtdDma0Source(dev, n) \ - writel((n) & 0xf, devpriv->las0+LAS0_DMA0_SRC) - -/* Set source for DMA 1 (write only, shadow?) */ -#define RtdDma1Source(dev, n) \ - writel((n) & 0xf, devpriv->las0+LAS0_DMA1_SRC) - -/* Reset board state for DMA 0 */ -#define RtdDma0Reset(dev) \ - writel(0, devpriv->las0+LAS0_DMA0_RESET) - -/* Reset board state for DMA 1 */ -#define RtdDma1Reset(dev) \ - writel(0, devpriv->las0+LAS0_DMA1_SRC) - -/* PLX9080 interrupt mask and status */ -#define RtdPlxInterruptRead(dev) \ - readl(devpriv->lcfg+LCFG_ITCSR) -#define RtdPlxInterruptWrite(dev, v) \ - writel(v, devpriv->lcfg+LCFG_ITCSR) - -/* Set mode for DMA 0 */ -#define RtdDma0Mode(dev, m) \ - writel((m), devpriv->lcfg+LCFG_DMAMODE0) - -/* Set PCI address for DMA 0 */ -#define RtdDma0PciAddr(dev, a) \ - writel((a), devpriv->lcfg+LCFG_DMAPADR0) - -/* Set local address for DMA 0 */ -#define RtdDma0LocalAddr(dev, a) \ - writel((a), devpriv->lcfg+LCFG_DMALADR0) - -/* Set byte count for DMA 0 */ -#define RtdDma0Count(dev, c) \ - writel((c), devpriv->lcfg+LCFG_DMASIZ0) - -/* Set next descriptor for DMA 0 */ -#define RtdDma0Next(dev, a) \ - writel((a), devpriv->lcfg+LCFG_DMADPR0) - -/* Set mode for DMA 1 */ -#define RtdDma1Mode(dev, m) \ - writel((m), devpriv->lcfg+LCFG_DMAMODE1) - -/* Set PCI address for DMA 1 */ -#define RtdDma1PciAddr(dev, a) \ - writel((a), devpriv->lcfg+LCFG_DMAADR1) - -/* Set local address for DMA 1 */ -#define RtdDma1LocalAddr(dev, a) \ - writel((a), devpriv->lcfg+LCFG_DMALADR1) - -/* Set byte count for DMA 1 */ -#define RtdDma1Count(dev, c) \ - writel((c), devpriv->lcfg+LCFG_DMASIZ1) - -/* Set next descriptor for DMA 1 */ -#define RtdDma1Next(dev, a) \ - writel((a), devpriv->lcfg+LCFG_DMADPR1) - -/* Set control for DMA 0 (write only, shadow?) */ -#define RtdDma0Control(dev, n) \ - writeb(devpriv->dma0Control = (n), devpriv->lcfg+LCFG_DMACSR0) - -/* Get status for DMA 0 */ -#define RtdDma0Status(dev) \ - readb(devpriv->lcfg+LCFG_DMACSR0) - -/* Set control for DMA 1 (write only, shadow?) */ -#define RtdDma1Control(dev, n) \ - writeb(devpriv->dma1Control = (n), devpriv->lcfg+LCFG_DMACSR1) - -/* Get status for DMA 1 */ -#define RtdDma1Status(dev) \ - readb(devpriv->lcfg+LCFG_DMACSR1) - -/* - * The struct comedi_driver structure tells the Comedi core module - * which functions to call to configure/deconfigure (attac/detach) - * the board, and also about the kernel module that contains - * the device code. - */ -static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int rtd_detach(struct comedi_device *dev); - -static struct comedi_driver rtd520Driver = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = rtd_attach, - .detach = rtd_detach, -}; - -static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int rtd_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int rtd_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int rtd_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_cmd *cmd); -static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s); -/* static int rtd_ai_poll (struct comedi_device *dev,struct comedi_subdevice *s); */ -static int rtd_ns_to_timer(unsigned int *ns, int roundMode); -static irqreturn_t rtd_interrupt(int irq, void *d); -static int rtd520_probe_fifo_depth(struct comedi_device *dev); - /* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ /* board name and options flags */ - struct comedi_subdevice *s; - struct pci_dev *pcidev; - int ret; - resource_size_t physLas0; /* configuration */ - resource_size_t physLas1; /* data area */ - resource_size_t physLcfg; /* PLX9080 */ -#ifdef USE_DMA - int index; -#endif - - printk(KERN_INFO "comedi%d: rtd520 attaching.\n", dev->minor); - -#if defined(CONFIG_COMEDI_DEBUG) && defined(USE_DMA) - /* You can set this a load time: modprobe comedi comedi_debug=1 */ - if (0 == comedi_debug) /* force DMA debug printks */ - comedi_debug = 1; -#endif - - /* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct rtdPrivate)) < 0) - return -ENOMEM; - - /* - * Probe the device to determine what device in the series it is. - */ - for (pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, NULL); - pcidev != NULL; - pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, pcidev)) { - int i; - - if (it->options[0] || it->options[1]) { - if (pcidev->bus->number != it->options[0] - || PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - for (i = 0; i < ARRAY_SIZE(rtd520Boards); ++i) { - if (pcidev->device == rtd520Boards[i].device_id) { - dev->board_ptr = &rtd520Boards[i]; - break; - } - } - if (dev->board_ptr) - break; /* found one */ - } - if (!pcidev) { - if (it->options[0] && it->options[1]) { - printk(KERN_INFO "No RTD card at bus=%d slot=%d.\n", - it->options[0], it->options[1]); - } else { - printk(KERN_INFO "No RTD card found.\n"); - } - return -EIO; - } - devpriv->pci_dev = pcidev; - dev->board_name = thisboard->name; - - ret = comedi_pci_enable(pcidev, DRV_NAME); - if (ret < 0) { - printk(KERN_INFO "Failed to enable PCI device and request regions.\n"); - return ret; - } - devpriv->got_regions = 1; - - /* - * Initialize base addresses - */ - /* Get the physical address from PCI config */ - physLas0 = pci_resource_start(devpriv->pci_dev, LAS0_PCIINDEX); - physLas1 = pci_resource_start(devpriv->pci_dev, LAS1_PCIINDEX); - physLcfg = pci_resource_start(devpriv->pci_dev, LCFG_PCIINDEX); - /* Now have the kernel map this into memory */ - /* ASSUME page aligned */ - devpriv->las0 = ioremap_nocache(physLas0, LAS0_PCISIZE); - devpriv->las1 = ioremap_nocache(physLas1, LAS1_PCISIZE); - devpriv->lcfg = ioremap_nocache(physLcfg, LCFG_PCISIZE); - - if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg) - return -ENOMEM; - - - DPRINTK("%s: LAS0=%llx, LAS1=%llx, CFG=%llx.\n", dev->board_name, - (unsigned long long)physLas0, (unsigned long long)physLas1, - (unsigned long long)physLcfg); - { /* The RTD driver does this */ - unsigned char pci_latency; - u16 revision; - /*uint32_t epld_version; */ - - pci_read_config_word(devpriv->pci_dev, PCI_REVISION_ID, - &revision); - DPRINTK("%s: PCI revision %d.\n", dev->board_name, revision); - - pci_read_config_byte(devpriv->pci_dev, - PCI_LATENCY_TIMER, &pci_latency); - if (pci_latency < 32) { - printk(KERN_INFO "%s: PCI latency changed from %d to %d\n", - dev->board_name, pci_latency, 32); - pci_write_config_byte(devpriv->pci_dev, - PCI_LATENCY_TIMER, 32); - } else { - DPRINTK("rtd520: PCI latency = %d\n", pci_latency); - } - - /* Undocumented EPLD version (doesn't match RTD driver results) */ - /*DPRINTK ("rtd520: Reading epld from %p\n", - devpriv->las0+0); - epld_version = readl (devpriv->las0+0); - if ((epld_version & 0xF0) >> 4 == 0x0F) { - DPRINTK("rtd520: pre-v8 EPLD. (%x)\n", epld_version); - } else { - DPRINTK("rtd520: EPLD version %x.\n", epld_version >> 4); - } */ - } - - /* Show board configuration */ - printk("%s:", dev->board_name); - - /* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 4) < 0) - return -ENOMEM; - - - s = dev->subdevices + 0; - dev->read_subdev = s; - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = - SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ; - s->n_chan = thisboard->aiChans; - s->maxdata = (1 << thisboard->aiBits) - 1; - if (thisboard->aiMaxGain <= 32) - s->range_table = &rtd_ai_7520_range; - else - s->range_table = &rtd_ai_4520_range; - - s->len_chanlist = RTD_MAX_CHANLIST; /* devpriv->fifoLen */ - s->insn_read = rtd_ai_rinsn; - s->do_cmd = rtd_ai_cmd; - s->do_cmdtest = rtd_ai_cmdtest; - s->cancel = rtd_ai_cancel; - /* s->poll = rtd_ai_poll; *//* not ready yet */ - - s = dev->subdevices + 1; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; - s->maxdata = (1 << thisboard->aiBits) - 1; - s->range_table = &rtd_ao_range; - s->insn_write = rtd_ao_winsn; - s->insn_read = rtd_ao_rinsn; - - s = dev->subdevices + 2; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - /* we only support port 0 right now. Ignoring port 1 and user IO */ - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = rtd_dio_insn_bits; - s->insn_config = rtd_dio_insn_config; - - /* timer/counter subdevices (not currently supported) */ - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 3; - s->maxdata = 0xffff; - - /* initialize board, per RTD spec */ - /* also, initialize shadow registers */ - RtdResetBoard(dev); - udelay(100); /* needed? */ - RtdPlxInterruptWrite(dev, 0); - RtdInterruptMask(dev, 0); /* and sets shadow */ - RtdInterruptClearMask(dev, ~0); /* and sets shadow */ - RtdInterruptClear(dev); /* clears bits set by mask */ - RtdInterruptOverrunClear(dev); - RtdClearCGT(dev); - RtdAdcClearFifo(dev); - RtdDacClearFifo(dev, 0); - RtdDacClearFifo(dev, 1); - /* clear digital IO fifo */ - RtdDioStatusWrite(dev, 0); /* safe state, set shadow */ - RtdUtcCtrlPut(dev, 0, 0x30); /* safe state, set shadow */ - RtdUtcCtrlPut(dev, 1, 0x30); /* safe state, set shadow */ - RtdUtcCtrlPut(dev, 2, 0x30); /* safe state, set shadow */ - RtdUtcCtrlPut(dev, 3, 0); /* safe state, set shadow */ - /* TODO: set user out source ??? */ - - /* check if our interrupt is available and get it */ - ret = request_irq(devpriv->pci_dev->irq, rtd_interrupt, - IRQF_SHARED, DRV_NAME, dev); - - if (ret < 0) { - printk("Could not get interrupt! (%u)\n", - devpriv->pci_dev->irq); - return ret; - } - dev->irq = devpriv->pci_dev->irq; - printk("( irq=%u )", dev->irq); - - ret = rtd520_probe_fifo_depth(dev); - if (ret < 0) - return ret; - - devpriv->fifoLen = ret; - printk("( fifoLen=%d )", devpriv->fifoLen); - -#ifdef USE_DMA - if (dev->irq > 0) { - printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT); - /* The PLX9080 has 2 DMA controllers, but there could be 4 sources: - ADC, digital, DAC1, and DAC2. Since only the ADC supports cmd mode - right now, this isn't an issue (yet) */ - devpriv->dma0Offset = 0; - - for (index = 0; index < DMA_CHAIN_COUNT; index++) { - devpriv->dma0Buff[index] = - pci_alloc_consistent(devpriv->pci_dev, - sizeof(u16) * - devpriv->fifoLen / 2, - &devpriv-> - dma0BuffPhysAddr[index]); - if (devpriv->dma0Buff[index] == NULL) { - ret = -ENOMEM; - goto rtd_attach_die_error; - } - /*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n", - index, - devpriv->dma0Buff[index], devpriv->dma0BuffPhysAddr[index]); */ - } - - /* setup DMA descriptor ring (use cpu_to_le32 for byte ordering?) */ - devpriv->dma0Chain = - pci_alloc_consistent(devpriv->pci_dev, - sizeof(struct plx_dma_desc) * - DMA_CHAIN_COUNT, - &devpriv->dma0ChainPhysAddr); - for (index = 0; index < DMA_CHAIN_COUNT; index++) { - devpriv->dma0Chain[index].pci_start_addr = - devpriv->dma0BuffPhysAddr[index]; - devpriv->dma0Chain[index].local_start_addr = - DMALADDR_ADC; - devpriv->dma0Chain[index].transfer_size = - sizeof(u16) * devpriv->fifoLen / 2; - devpriv->dma0Chain[index].next = - (devpriv->dma0ChainPhysAddr + ((index + - 1) % - (DMA_CHAIN_COUNT)) - * sizeof(devpriv->dma0Chain[0])) - | DMA_TRANSFER_BITS; - /*DPRINTK ("ring[%d] @%lx PCI: %x, local: %x, N: 0x%x, next: %x\n", - index, - ((long)devpriv->dma0ChainPhysAddr - + (index * sizeof(devpriv->dma0Chain[0]))), - devpriv->dma0Chain[index].pci_start_addr, - devpriv->dma0Chain[index].local_start_addr, - devpriv->dma0Chain[index].transfer_size, - devpriv->dma0Chain[index].next); */ - } - - if (devpriv->dma0Chain == NULL) { - ret = -ENOMEM; - goto rtd_attach_die_error; - } - - RtdDma0Mode(dev, DMA_MODE_BITS); - RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL); /* set DMA trigger source */ - } else { - printk(KERN_INFO "( no IRQ->no DMA )"); - } -#endif /* USE_DMA */ - - if (dev->irq) { /* enable plx9080 interrupts */ - RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE); - } + Given a desired period and the clock period (both in ns), + return the proper counter value (divider-1). + Sets the original period to be the true value. + Note: you have to check if the value is larger than the counter range! +*/ +static int rtd_ns_to_timer_base(unsigned int *nanosec, + int round_mode, int base) +{ + int divider; - printk("\ncomedi%d: rtd520 driver attached.\n", dev->minor); - - return 1; - -#if 0 - /* hit an error, clean up memory and return ret */ -/* rtd_attach_die_error: */ -#ifdef USE_DMA - for (index = 0; index < DMA_CHAIN_COUNT; index++) { - if (NULL != devpriv->dma0Buff[index]) { /* free buffer memory */ - pci_free_consistent(devpriv->pci_dev, - sizeof(u16) * devpriv->fifoLen / 2, - devpriv->dma0Buff[index], - devpriv->dma0BuffPhysAddr[index]); - devpriv->dma0Buff[index] = NULL; - } - } - if (NULL != devpriv->dma0Chain) { - pci_free_consistent(devpriv->pci_dev, - sizeof(struct plx_dma_desc) - * DMA_CHAIN_COUNT, - devpriv->dma0Chain, - devpriv->dma0ChainPhysAddr); - devpriv->dma0Chain = NULL; - } -#endif /* USE_DMA */ - /* subdevices and priv are freed by the core */ - if (dev->irq) { - /* disable interrupt controller */ - RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev) - & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E)); - free_irq(dev->irq, dev); + switch (round_mode) { + case TRIG_ROUND_NEAREST: + default: + divider = (*nanosec + base / 2) / base; + break; + case TRIG_ROUND_DOWN: + divider = (*nanosec) / base; + break; + case TRIG_ROUND_UP: + divider = (*nanosec + base - 1) / base; + break; } + if (divider < 2) + divider = 2; /* min is divide by 2 */ - /* release all regions that were allocated */ - if (devpriv->las0) - iounmap(devpriv->las0); - - if (devpriv->las1) - iounmap(devpriv->las1); - - if (devpriv->lcfg) - iounmap(devpriv->lcfg); - - if (devpriv->pci_dev) - pci_dev_put(devpriv->pci_dev); + /* Note: we don't check for max, because different timers + have different ranges */ - return ret; -#endif + *nanosec = base * divider; + return divider - 1; /* countdown is divisor+1 */ } /* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int rtd_detach(struct comedi_device *dev) + Given a desired period (in ns), + return the proper counter value (divider-1) for the internal clock. + Sets the original period to be the true value. +*/ +static int rtd_ns_to_timer(unsigned int *ns, int round_mode) { -#ifdef USE_DMA - int index; -#endif - - DPRINTK("comedi%d: rtd520: removing (%ld ints)\n", - dev->minor, (devpriv ? devpriv->intCount : 0L)); - if (devpriv && devpriv->lcfg) { - DPRINTK - ("(int status 0x%x, overrun status 0x%x, fifo status 0x%x)...\n", - 0xffff & RtdInterruptStatus(dev), - 0xffff & RtdInterruptOverrunStatus(dev), - (0xffff & RtdFifoStatus(dev)) ^ 0x6666); - } - - if (devpriv) { - /* Shut down any board ops by resetting it */ -#ifdef USE_DMA - if (devpriv->lcfg) { - RtdDma0Control(dev, 0); /* disable DMA */ - RtdDma1Control(dev, 0); /* disable DMA */ - RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE); - } -#endif /* USE_DMA */ - if (devpriv->las0) { - RtdResetBoard(dev); - RtdInterruptMask(dev, 0); - RtdInterruptClearMask(dev, ~0); - RtdInterruptClear(dev); /* clears bits set by mask */ - } -#ifdef USE_DMA - /* release DMA */ - for (index = 0; index < DMA_CHAIN_COUNT; index++) { - if (NULL != devpriv->dma0Buff[index]) { - pci_free_consistent(devpriv->pci_dev, - sizeof(u16) * - devpriv->fifoLen / 2, - devpriv->dma0Buff[index], - devpriv-> - dma0BuffPhysAddr[index]); - devpriv->dma0Buff[index] = NULL; - } - } - if (NULL != devpriv->dma0Chain) { - pci_free_consistent(devpriv->pci_dev, - sizeof(struct plx_dma_desc) * - DMA_CHAIN_COUNT, devpriv->dma0Chain, - devpriv->dma0ChainPhysAddr); - devpriv->dma0Chain = NULL; - } -#endif /* USE_DMA */ - - /* release IRQ */ - if (dev->irq) { - /* disable interrupt controller */ - RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev) - & ~(ICS_PLIE | ICS_DMA0_E | - ICS_DMA1_E)); - free_irq(dev->irq, dev); - } - - /* release all regions that were allocated */ - if (devpriv->las0) - iounmap(devpriv->las0); - - if (devpriv->las1) - iounmap(devpriv->las1); - - if (devpriv->lcfg) - iounmap(devpriv->lcfg); - - if (devpriv->pci_dev) { - if (devpriv->got_regions) - comedi_pci_disable(devpriv->pci_dev); - - pci_dev_put(devpriv->pci_dev); - } - } - - printk(KERN_INFO "comedi%d: rtd520: removed.\n", dev->minor); - - return 0; + return rtd_ns_to_timer_base(ns, round_mode, RTD_CLOCK_BASE); } /* Convert a single comedi channel-gain entry to a RTD520 table entry */ -static unsigned short rtdConvertChanGain(struct comedi_device *dev, - unsigned int comediChan, int chanIndex) -{ /* index in channel list */ - unsigned int chan, range, aref; +static unsigned short rtd_convert_chan_gain(struct comedi_device *dev, + unsigned int chanspec, int index) +{ + const struct rtd_boardinfo *board = comedi_board(dev); + struct rtd_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(chanspec); + unsigned int range = CR_RANGE(chanspec); + unsigned int aref = CR_AREF(chanspec); unsigned short r = 0; - chan = CR_CHAN(comediChan); - range = CR_RANGE(comediChan); - aref = CR_AREF(comediChan); - r |= chan & 0xf; /* Note: we also setup the channel list bipolar flag array */ - if (range < thisboard->range10Start) { /* first batch are +-5 */ - r |= 0x000; /* +-5 range */ - r |= (range & 0x7) << 4; /* gain */ - CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex); - } else if (range < thisboard->rangeUniStart) { /* second batch are +-10 */ - r |= 0x100; /* +-10 range */ - r |= ((range - thisboard->range10Start) & 0x7) << 4; /* gain */ - CHAN_ARRAY_SET(devpriv->chanBipolar, chanIndex); - } else { /* last batch is +10 */ - r |= 0x200; /* +10 range */ - r |= ((range - thisboard->rangeUniStart) & 0x7) << 4; /* gain */ - CHAN_ARRAY_CLEAR(devpriv->chanBipolar, chanIndex); + if (range < board->range_bip10) { + /* +-5 range */ + r |= 0x000; + r |= (range & 0x7) << 4; + __set_bit(index, devpriv->chan_is_bipolar); + } else if (range < board->range_uni10) { + /* +-10 range */ + r |= 0x100; + r |= ((range - board->range_bip10) & 0x7) << 4; + __set_bit(index, devpriv->chan_is_bipolar); + } else { + /* +10 range */ + r |= 0x200; + r |= ((range - board->range_uni10) & 0x7) << 4; + __clear_bit(index, devpriv->chan_is_bipolar); } switch (aref) { @@ -1225,8 +481,6 @@ static unsigned short rtdConvertChanGain(struct comedi_device *dev, case AREF_OTHER: /* ??? */ break; } - /*printk ("chan=%d r=%d a=%d -> 0x%x\n", - chan, range, aref, r); */ return r; } @@ -1236,17 +490,21 @@ static unsigned short rtdConvertChanGain(struct comedi_device *dev, static void rtd_load_channelgain_list(struct comedi_device *dev, unsigned int n_chan, unsigned int *list) { + struct rtd_private *devpriv = dev->private; + if (n_chan > 1) { /* setup channel gain table */ int ii; - RtdClearCGT(dev); - RtdEnableCGT(dev, 1); /* enable table */ + + writel(0, devpriv->las0 + LAS0_CGT_CLEAR); + writel(1, devpriv->las0 + LAS0_CGT_ENABLE); for (ii = 0; ii < n_chan; ii++) { - RtdWriteCGTable(dev, rtdConvertChanGain(dev, list[ii], - ii)); + writel(rtd_convert_chan_gain(dev, list[ii], ii), + devpriv->las0 + LAS0_CGT_WRITE); } } else { /* just use the channel gain latch */ - RtdEnableCGT(dev, 0); /* disable table, enable latch */ - RtdWriteCGLatch(dev, rtdConvertChanGain(dev, list[0], 0)); + writel(0, devpriv->las0 + LAS0_CGT_ENABLE); + writel(rtd_convert_chan_gain(dev, list[0], 0), + devpriv->las0 + LAS0_CGL_WRITE); } } @@ -1254,91 +512,90 @@ static void rtd_load_channelgain_list(struct comedi_device *dev, empty status flag clears */ static int rtd520_probe_fifo_depth(struct comedi_device *dev) { + struct rtd_private *devpriv = dev->private; unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND); unsigned i; static const unsigned limit = 0x2000; unsigned fifo_size = 0; - RtdAdcClearFifo(dev); + writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); rtd_load_channelgain_list(dev, 1, &chanspec); - RtdAdcConversionSource(dev, 0); /* software */ + /* ADC conversion trigger source: SOFTWARE */ + writel(0, devpriv->las0 + LAS0_ADC_CONVERSION); /* convert samples */ for (i = 0; i < limit; ++i) { unsigned fifo_status; /* trigger conversion */ - RtdAdcStart(dev); + writew(0, devpriv->las0 + LAS0_ADC); udelay(1); - fifo_status = RtdFifoStatus(dev); + fifo_status = readl(devpriv->las0 + LAS0_ADC); if ((fifo_status & FS_ADC_HEMPTY) == 0) { fifo_size = 2 * i; break; } } if (i == limit) { - printk(KERN_INFO "\ncomedi: %s: failed to probe fifo size.\n", DRV_NAME); + dev_info(dev->class_dev, "failed to probe fifo size.\n"); return -EIO; } - RtdAdcClearFifo(dev); + writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); if (fifo_size != 0x400 && fifo_size != 0x2000) { - printk - (KERN_INFO "\ncomedi: %s: unexpected fifo size of %i, expected 1024 or 8192.\n", - DRV_NAME, fifo_size); + dev_info(dev->class_dev, + "unexpected fifo size of %i, expected 1024 or 8192.\n", + fifo_size); return -EIO; } return fifo_size; } -/* - "instructions" read/write data in "one-shot" or "software-triggered" - mode (simplest case). - This doesn't use interrupts. +static int rtd_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct rtd_private *devpriv = dev->private; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & FS_ADC_NOT_EMPTY) + return 0; + return -EBUSY; +} - Note, we don't do any settling delays. Use a instruction list to - select, delay, then read. - */ static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, ii; - int stat; + struct rtd_private *devpriv = dev->private; + int ret; + int n; /* clear any old fifo data */ - RtdAdcClearFifo(dev); + writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); /* write channel to multiplexer and clear channel gain table */ rtd_load_channelgain_list(dev, 1, &insn->chanspec); - /* set conversion source */ - RtdAdcConversionSource(dev, 0); /* software */ + /* ADC conversion trigger source: SOFTWARE */ + writel(0, devpriv->las0 + LAS0_ADC_CONVERSION); /* convert n samples */ for (n = 0; n < insn->n; n++) { - s16 d; + unsigned short d; /* trigger conversion */ - RtdAdcStart(dev); + writew(0, devpriv->las0 + LAS0_ADC); - for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) { - stat = RtdFifoStatus(dev); - if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */ - break; - WAIT_QUIETLY; - } - if (ii >= RTD_ADC_TIMEOUT) { - DPRINTK - ("rtd520: Error: ADC never finished! FifoStatus=0x%x\n", - stat ^ 0x6666); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, rtd_ai_eoc, 0); + if (ret) + return ret; /* read data */ - d = RtdAdcFifoGet(dev); /* get 2s comp value */ - /*printk ("rtd520: Got 0x%x after %d usec\n", d, ii+1); */ + d = readw(devpriv->las1 + LAS1_ADC_FIFO); d = d >> 3; /* low 3 bits are marker lines */ - if (CHAN_ARRAY_TEST(devpriv->chanBipolar, 0)) - data[n] = d + 2048; /* convert to comedi unsigned data */ - else - data[n] = d; + if (test_bit(0, devpriv->chan_is_bipolar)) + /* convert to comedi unsigned data */ + d = comedi_offset_munge(s, d); + data[n] = d & s->maxdata; } /* return the number of samples read/written */ @@ -1354,36 +611,29 @@ static int rtd_ai_rinsn(struct comedi_device *dev, static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, int count) { + struct rtd_private *devpriv = dev->private; int ii; for (ii = 0; ii < count; ii++) { - short sample; - s16 d; + unsigned short d; - if (0 == devpriv->aiCount) { /* done */ - d = RtdAdcFifoGet(dev); /* Read N and discard */ + if (0 == devpriv->ai_count) { /* done */ + d = readw(devpriv->las1 + LAS1_ADC_FIFO); continue; } -#if 0 - if (0 == (RtdFifoStatus(dev) & FS_ADC_NOT_EMPTY)) { /* DEBUG */ - DPRINTK("comedi: READ OOPS on %d of %d\n", ii + 1, - count); - break; - } -#endif - d = RtdAdcFifoGet(dev); /* get 2s comp value */ + d = readw(devpriv->las1 + LAS1_ADC_FIFO); d = d >> 3; /* low 3 bits are marker lines */ - if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) - sample = d + 2048; /* convert to comedi unsigned data */ - else - sample = d; + if (test_bit(s->async->cur_chan, devpriv->chan_is_bipolar)) + /* convert to comedi unsigned data */ + d = comedi_offset_munge(s, d); + d &= s->maxdata; - if (!comedi_buf_put(s->async, sample)) + if (!comedi_buf_put(s, d)) return -1; - if (devpriv->aiCount > 0) /* < 0, means read forever */ - devpriv->aiCount--; + if (devpriv->ai_count > 0) /* < 0, means read forever */ + devpriv->ai_count--; } return 0; } @@ -1393,293 +643,112 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s, */ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s) { - while (RtdFifoStatus(dev) & FS_ADC_NOT_EMPTY) { /* 1 -> not empty */ - short sample; - s16 d = RtdAdcFifoGet(dev); /* get 2s comp value */ + struct rtd_private *devpriv = dev->private; + + while (readl(devpriv->las0 + LAS0_ADC) & FS_ADC_NOT_EMPTY) { + unsigned short d = readw(devpriv->las1 + LAS1_ADC_FIFO); - if (0 == devpriv->aiCount) { /* done */ + if (0 == devpriv->ai_count) { /* done */ continue; /* read rest */ } d = d >> 3; /* low 3 bits are marker lines */ - if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) - sample = d + 2048; /* convert to comedi unsigned data */ - else - sample = d; + if (test_bit(s->async->cur_chan, devpriv->chan_is_bipolar)) + /* convert to comedi unsigned data */ + d = comedi_offset_munge(s, d); + d &= s->maxdata; - if (!comedi_buf_put(s->async, sample)) + if (!comedi_buf_put(s, d)) return -1; - if (devpriv->aiCount > 0) /* < 0, means read forever */ - devpriv->aiCount--; + if (devpriv->ai_count > 0) /* < 0, means read forever */ + devpriv->ai_count--; } return 0; } -#ifdef USE_DMA -/* - Terminate a DMA transfer and wait for everything to quiet down -*/ -void abort_dma(struct comedi_device *dev, unsigned int channel) -{ /* DMA channel 0, 1 */ - unsigned long dma_cs_addr; /* the control/status register */ - uint8_t status; - unsigned int ii; - /* unsigned long flags; */ - - dma_cs_addr = (unsigned long)devpriv->lcfg - + ((channel == 0) ? LCFG_DMACSR0 : LCFG_DMACSR1); - - /* spinlock for plx dma control/status reg */ - /* spin_lock_irqsave( &dev->spinlock, flags ); */ - - /* abort dma transfer if necessary */ - status = readb(dma_cs_addr); - if ((status & PLX_DMA_EN_BIT) == 0) { /* not enabled (Error?) */ - DPRINTK("rtd520: AbortDma on non-active channel %d (0x%x)\n", - channel, status); - goto abortDmaExit; - } - - /* wait to make sure done bit is zero (needed?) */ - for (ii = 0; (status & PLX_DMA_DONE_BIT) && ii < RTD_DMA_TIMEOUT; ii++) { - WAIT_QUIETLY; - status = readb(dma_cs_addr); - } - if (status & PLX_DMA_DONE_BIT) { - printk("rtd520: Timeout waiting for dma %i done clear\n", - channel); - goto abortDmaExit; - } - - /* disable channel (required) */ - writeb(0, dma_cs_addr); - udelay(1); /* needed?? */ - /* set abort bit for channel */ - writeb(PLX_DMA_ABORT_BIT, dma_cs_addr); - - /* wait for dma done bit to be set */ - status = readb(dma_cs_addr); - for (ii = 0; - (status & PLX_DMA_DONE_BIT) == 0 && ii < RTD_DMA_TIMEOUT; ii++) { - status = readb(dma_cs_addr); - WAIT_QUIETLY; - } - if ((status & PLX_DMA_DONE_BIT) == 0) { - printk("rtd520: Timeout waiting for dma %i done set\n", - channel); - } - -abortDmaExit: - /* spin_unlock_irqrestore( &dev->spinlock, flags ); */ -} - -/* - Process what is in the DMA transfer buffer and pass to comedi - Note: this is not re-entrant -*/ -static int ai_process_dma(struct comedi_device *dev, struct comedi_subdevice *s) -{ - int ii, n; - s16 *dp; - - if (devpriv->aiCount == 0) /* transfer already complete */ - return 0; - - dp = devpriv->dma0Buff[devpriv->dma0Offset]; - for (ii = 0; ii < devpriv->fifoLen / 2;) { /* convert samples */ - short sample; - - if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) { - sample = (*dp >> 3) + 2048; /* convert to comedi unsigned data */ - else - sample = *dp >> 3; /* low 3 bits are marker lines */ - - *dp++ = sample; /* put processed value back */ - - if (++s->async->cur_chan >= s->async->cmd.chanlist_len) - s->async->cur_chan = 0; - - ++ii; /* number ready to transfer */ - if (devpriv->aiCount > 0) { /* < 0, means read forever */ - if (--devpriv->aiCount == 0) { /* done */ - /*DPRINTK ("rtd520: Final %d samples\n", ii); */ - break; - } - } - } - - /* now pass the whole array to the comedi buffer */ - dp = devpriv->dma0Buff[devpriv->dma0Offset]; - n = comedi_buf_write_alloc(s->async, ii * sizeof(s16)); - if (n < (ii * sizeof(s16))) { /* any residual is an error */ - DPRINTK("rtd520:ai_process_dma buffer overflow %d samples!\n", - ii - (n / sizeof(s16))); - s->async->events |= COMEDI_CB_ERROR; - return -1; - } - comedi_buf_memcpy_to(s->async, 0, dp, n); - comedi_buf_write_free(s->async, n); - - /* always at least 1 scan -- 1/2 FIFO is larger than our max scan list */ - s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - - if (++devpriv->dma0Offset >= DMA_CHAIN_COUNT) { /* next buffer */ - devpriv->dma0Offset = 0; - } - return 0; -} -#endif /* USE_DMA */ - /* Handle all rtd520 interrupts. Runs atomically and is never re-entered. This is a "slow handler"; other interrupts may be active. The data conversion may someday happen in a "bottom half". */ -static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */ - void *d) -{ /* our data *//* cpu context (ignored) */ - struct comedi_device *dev = d; /* must be called "dev" for devpriv */ +static irqreturn_t rtd_interrupt(int irq, void *d) +{ + struct comedi_device *dev = d; + struct comedi_subdevice *s = dev->read_subdev; + struct rtd_private *devpriv = dev->private; + u32 overrun; u16 status; - u16 fifoStatus; - struct comedi_subdevice *s = dev->subdevices + 0; /* analog in subdevice */ + u16 fifo_status; if (!dev->attached) return IRQ_NONE; - devpriv->intCount++; /* DEBUG statistics */ - - fifoStatus = RtdFifoStatus(dev); + fifo_status = readl(devpriv->las0 + LAS0_ADC); /* check for FIFO full, this automatically halts the ADC! */ - if (!(fifoStatus & FS_ADC_NOT_FULL)) { /* 0 -> full */ - DPRINTK("rtd520: FIFO full! fifo_status=0x%x\n", (fifoStatus ^ 0x6666) & 0x7777); /* should be all 0s */ - goto abortTransfer; - } -#ifdef USE_DMA - if (devpriv->flags & DMA0_ACTIVE) { /* Check DMA */ - u32 istatus = RtdPlxInterruptRead(dev); - - if (istatus & ICS_DMA0_A) { - if (ai_process_dma(dev, s) < 0) { - DPRINTK - ("rtd520: comedi read buffer overflow (DMA) with %ld to go!\n", - devpriv->aiCount); - RtdDma0Control(dev, - (devpriv->dma0Control & - ~PLX_DMA_START_BIT) - | PLX_CLEAR_DMA_INTR_BIT); - goto abortTransfer; - } - - /*DPRINTK ("rtd520: DMA transfer: %ld to go, istatus %x\n", - devpriv->aiCount, istatus); */ - RtdDma0Control(dev, - (devpriv-> - dma0Control & ~PLX_DMA_START_BIT) - | PLX_CLEAR_DMA_INTR_BIT); - if (0 == devpriv->aiCount) { /* counted down */ - DPRINTK("rtd520: Samples Done (DMA).\n"); - goto transferDone; - } - comedi_event(dev, s); - } else { - /*DPRINTK ("rtd520: No DMA ready: istatus %x\n", istatus); */ - } - } - /* Fall through and check for other interrupt sources */ -#endif /* USE_DMA */ + if (!(fifo_status & FS_ADC_NOT_FULL)) /* 0 -> full */ + goto xfer_abort; - status = RtdInterruptStatus(dev); + status = readw(devpriv->las0 + LAS0_IT); /* if interrupt was not caused by our board, or handled above */ if (0 == status) return IRQ_HANDLED; if (status & IRQM_ADC_ABOUT_CNT) { /* sample count -> read FIFO */ - /* since the priority interrupt controller may have queued a sample - counter interrupt, even though we have already finished, - we must handle the possibility that there is no data here */ - if (!(fifoStatus & FS_ADC_HEMPTY)) { /* 0 -> 1/2 full */ - /*DPRINTK("rtd520: Sample int, reading 1/2FIFO. fifo_status 0x%x\n", - (fifoStatus ^ 0x6666) & 0x7777); */ - if (ai_read_n(dev, s, devpriv->fifoLen / 2) < 0) { - DPRINTK - ("rtd520: comedi read buffer overflow (1/2FIFO) with %ld to go!\n", - devpriv->aiCount); - goto abortTransfer; - } - if (0 == devpriv->aiCount) { /* counted down */ - DPRINTK("rtd520: Samples Done (1/2). fifo_status was 0x%x\n", (fifoStatus ^ 0x6666) & 0x7777); /* should be all 0s */ - goto transferDone; - } + /* + * since the priority interrupt controller may have queued + * a sample counter interrupt, even though we have already + * finished, we must handle the possibility that there is + * no data here + */ + if (!(fifo_status & FS_ADC_HEMPTY)) { + /* FIFO half full */ + if (ai_read_n(dev, s, devpriv->fifosz / 2) < 0) + goto xfer_abort; + + if (0 == devpriv->ai_count) + goto xfer_done; + comedi_event(dev, s); - } else if (devpriv->transCount > 0) { /* read often */ - /*DPRINTK("rtd520: Sample int, reading %d fifo_status 0x%x\n", - devpriv->transCount, (fifoStatus ^ 0x6666) & 0x7777); */ - if (fifoStatus & FS_ADC_NOT_EMPTY) { /* 1 -> not empty */ - if (ai_read_n(dev, s, devpriv->transCount) < 0) { - DPRINTK - ("rtd520: comedi read buffer overflow (N) with %ld to go!\n", - devpriv->aiCount); - goto abortTransfer; - } - if (0 == devpriv->aiCount) { /* counted down */ - DPRINTK - ("rtd520: Samples Done (N). fifo_status was 0x%x\n", - (fifoStatus ^ 0x6666) & 0x7777); - goto transferDone; - } + } else if (devpriv->xfer_count > 0) { + if (fifo_status & FS_ADC_NOT_EMPTY) { + /* FIFO not empty */ + if (ai_read_n(dev, s, devpriv->xfer_count) < 0) + goto xfer_abort; + + if (0 == devpriv->ai_count) + goto xfer_done; + comedi_event(dev, s); } - } else { /* wait for 1/2 FIFO (old) */ - DPRINTK - ("rtd520: Sample int. Wait for 1/2. fifo_status 0x%x\n", - (fifoStatus ^ 0x6666) & 0x7777); } - } else { - DPRINTK("rtd520: unknown interrupt source!\n"); } - if (0xffff & RtdInterruptOverrunStatus(dev)) { /* interrupt overrun */ - DPRINTK - ("rtd520: Interrupt overrun with %ld to go! over_status=0x%x\n", - devpriv->aiCount, 0xffff & RtdInterruptOverrunStatus(dev)); - goto abortTransfer; - } + overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff; + if (overrun) + goto xfer_abort; /* clear the interrupt */ - RtdInterruptClearMask(dev, status); - RtdInterruptClear(dev); + writew(status, devpriv->las0 + LAS0_CLEAR); + readw(devpriv->las0 + LAS0_CLEAR); return IRQ_HANDLED; -abortTransfer: - RtdAdcClearFifo(dev); /* clears full flag */ +xfer_abort: + writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); s->async->events |= COMEDI_CB_ERROR; - devpriv->aiCount = 0; /* stop and don't transfer any more */ - /* fall into transferDone */ - -transferDone: - RtdPacerStopSource(dev, 0); /* stop on SOFTWARE stop */ - RtdPacerStop(dev); /* Stop PACER */ - RtdAdcConversionSource(dev, 0); /* software trigger only */ - RtdInterruptMask(dev, 0); /* mask out SAMPLE */ -#ifdef USE_DMA - if (devpriv->flags & DMA0_ACTIVE) { - RtdPlxInterruptWrite(dev, /* disable any more interrupts */ - RtdPlxInterruptRead(dev) & ~ICS_DMA0_E); - abort_dma(dev, 0); - devpriv->flags &= ~DMA0_ACTIVE; - /* if Using DMA, then we should have read everything by now */ - if (devpriv->aiCount > 0) { - DPRINTK("rtd520: Lost DMA data! %ld remain\n", - devpriv->aiCount); - } - } -#endif /* USE_DMA */ - - if (devpriv->aiCount > 0) { /* there shouldn't be anything left */ - fifoStatus = RtdFifoStatus(dev); - DPRINTK("rtd520: Finishing up. %ld remain, fifoStat=%x\n", devpriv->aiCount, (fifoStatus ^ 0x6666) & 0x7777); /* should read all 0s */ + devpriv->ai_count = 0; /* stop and don't transfer any more */ + /* fall into xfer_done */ + +xfer_done: + /* pacer stop source: SOFTWARE */ + writel(0, devpriv->las0 + LAS0_PACER_STOP); + writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */ + writel(0, devpriv->las0 + LAS0_ADC_CONVERSION); + writew(0, devpriv->las0 + LAS0_IT); + + if (devpriv->ai_count > 0) { /* there shouldn't be anything left */ + fifo_status = readl(devpriv->las0 + LAS0_ADC); ai_read_dregs(dev, s); /* read anything left in FIFO */ } @@ -1687,35 +756,20 @@ transferDone: comedi_event(dev, s); /* clear the interrupt */ - status = RtdInterruptStatus(dev); - RtdInterruptClearMask(dev, status); - RtdInterruptClear(dev); + status = readw(devpriv->las0 + LAS0_IT); + writew(status, devpriv->las0 + LAS0_CLEAR); + readw(devpriv->las0 + LAS0_CLEAR); - fifoStatus = RtdFifoStatus(dev); /* DEBUG */ - DPRINTK - ("rtd520: Acquisition complete. %ld ints, intStat=%x, overStat=%x\n", - devpriv->intCount, status, - 0xffff & RtdInterruptOverrunStatus(dev)); + fifo_status = readl(devpriv->las0 + LAS0_ADC); + overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff; return IRQ_HANDLED; } -#if 0 -/* - return the number of samples available -*/ -static int rtd_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) -{ - /* TODO: This needs to mask interrupts, read_dregs, and then re-enable */ - /* Not sure what to do if DMA is active */ - return s->async->buf_write_count - s->async->buf_read_count; -} -#endif - /* 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 executed by the cmd ioctl (asyncronously). + and then have it executed by the cmd ioctl (asynchronously). cmdtest returns 1,2,3,4 or 0, depending on which tests the command passes. @@ -1725,155 +779,112 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + unsigned int arg; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - + 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 2: make sure trigger sources are unique - and mutually compatible */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) { - err++; - } - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; + /* Step 2a : make sure trigger sources are unique */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + 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: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); if (cmd->scan_begin_src == TRIG_TIMER) { /* Note: these are time periods, not actual rates */ if (1 == cmd->chanlist_len) { /* no scanning */ - if (cmd->scan_begin_arg < RTD_MAX_SPEED_1) { - cmd->scan_begin_arg = RTD_MAX_SPEED_1; + 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); - err++; + err |= -EINVAL; } - if (cmd->scan_begin_arg > RTD_MIN_SPEED_1) { - cmd->scan_begin_arg = RTD_MIN_SPEED_1; + 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); - err++; + err |= -EINVAL; } } else { - if (cmd->scan_begin_arg < RTD_MAX_SPEED) { - cmd->scan_begin_arg = RTD_MAX_SPEED; + if (cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + RTD_MAX_SPEED)) { rtd_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_UP); - err++; + err |= -EINVAL; } - if (cmd->scan_begin_arg > RTD_MIN_SPEED) { - cmd->scan_begin_arg = RTD_MIN_SPEED; + if (cfc_check_trigger_arg_max(&cmd->scan_begin_arg, + RTD_MIN_SPEED)) { rtd_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_DOWN); - err++; + err |= -EINVAL; } } } else { /* external trigger */ /* should be level/edge, hi/lo specification here */ /* should specify multiple external triggers */ - if (cmd->scan_begin_arg > 9) { - cmd->scan_begin_arg = 9; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); } + if (cmd->convert_src == TRIG_TIMER) { if (1 == cmd->chanlist_len) { /* no scanning */ - if (cmd->convert_arg < RTD_MAX_SPEED_1) { - cmd->convert_arg = RTD_MAX_SPEED_1; + if (cfc_check_trigger_arg_min(&cmd->convert_arg, + RTD_MAX_SPEED_1)) { rtd_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_UP); - err++; + err |= -EINVAL; } - if (cmd->convert_arg > RTD_MIN_SPEED_1) { - cmd->convert_arg = RTD_MIN_SPEED_1; + if (cfc_check_trigger_arg_max(&cmd->convert_arg, + RTD_MIN_SPEED_1)) { rtd_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_DOWN); - err++; + err |= -EINVAL; } } else { - if (cmd->convert_arg < RTD_MAX_SPEED) { - cmd->convert_arg = RTD_MAX_SPEED; + if (cfc_check_trigger_arg_min(&cmd->convert_arg, + RTD_MAX_SPEED)) { rtd_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_UP); - err++; + err |= -EINVAL; } - if (cmd->convert_arg > RTD_MIN_SPEED) { - cmd->convert_arg = RTD_MIN_SPEED; + if (cfc_check_trigger_arg_max(&cmd->convert_arg, + RTD_MIN_SPEED)) { rtd_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_DOWN); - err++; + err |= -EINVAL; } } } else { /* external trigger */ /* see above */ - if (cmd->convert_arg > 9) { - cmd->convert_arg = 9; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9); } -#if 0 - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } -#endif + 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_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -1882,31 +893,21 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ - if (cmd->chanlist_len > RTD_MAX_CHANLIST) { - cmd->chanlist_len = RTD_MAX_CHANLIST; - err++; - } if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - rtd_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; - + arg = cmd->scan_begin_arg; + rtd_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } + if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - rtd_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - - if (cmd->scan_begin_src == TRIG_TIMER - && (cmd->scan_begin_arg - < (cmd->convert_arg * cmd->scan_end_arg))) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + rtd_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -1924,34 +925,18 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, */ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct rtd_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; int timer; /* stop anything currently running */ - RtdPacerStopSource(dev, 0); /* stop on SOFTWARE stop */ - RtdPacerStop(dev); /* make sure PACER is stopped */ - RtdAdcConversionSource(dev, 0); /* software trigger only */ - RtdInterruptMask(dev, 0); -#ifdef USE_DMA - if (devpriv->flags & DMA0_ACTIVE) { /* cancel anything running */ - RtdPlxInterruptWrite(dev, /* disable any more interrupts */ - RtdPlxInterruptRead(dev) & ~ICS_DMA0_E); - abort_dma(dev, 0); - devpriv->flags &= ~DMA0_ACTIVE; - if (RtdPlxInterruptRead(dev) & ICS_DMA0_A) { /*clear pending int */ - RtdDma0Control(dev, PLX_CLEAR_DMA_INTR_BIT); - } - } - RtdDma0Reset(dev); /* reset onboard state */ -#endif /* USE_DMA */ - RtdAdcClearFifo(dev); /* clear any old data */ - RtdInterruptOverrunClear(dev); - devpriv->intCount = 0; - - if (!dev->irq) { /* we need interrupts for this */ - DPRINTK("rtd520: ERROR! No interrupt available!\n"); - return -ENXIO; - } + /* pacer stop source: SOFTWARE */ + writel(0, devpriv->las0 + LAS0_PACER_STOP); + writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */ + writel(0, devpriv->las0 + LAS0_ADC_CONVERSION); + writew(0, devpriv->las0 + LAS0_IT); + writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); + writel(0, devpriv->las0 + LAS0_OVERRUN); /* start configuration */ /* load channel list and reset CGT */ @@ -1959,82 +944,81 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* setup the common case and override if needed */ if (cmd->chanlist_len > 1) { - /*DPRINTK ("rtd520: Multi channel setup\n"); */ - RtdPacerStartSource(dev, 0); /* software triggers pacer */ - RtdBurstStartSource(dev, 1); /* PACER triggers burst */ - RtdAdcConversionSource(dev, 2); /* BURST triggers ADC */ + /* pacer start source: SOFTWARE */ + writel(0, devpriv->las0 + LAS0_PACER_START); + /* burst trigger source: PACER */ + writel(1, devpriv->las0 + LAS0_BURST_START); + /* ADC conversion trigger source: BURST */ + writel(2, devpriv->las0 + LAS0_ADC_CONVERSION); } else { /* single channel */ - /*DPRINTK ("rtd520: single channel setup\n"); */ - RtdPacerStartSource(dev, 0); /* software triggers pacer */ - RtdAdcConversionSource(dev, 1); /* PACER triggers ADC */ + /* pacer start source: SOFTWARE */ + writel(0, devpriv->las0 + LAS0_PACER_START); + /* ADC conversion trigger source: PACER */ + writel(1, devpriv->las0 + LAS0_ADC_CONVERSION); } - RtdAboutCounter(dev, devpriv->fifoLen / 2 - 1); /* 1/2 FIFO */ + writel((devpriv->fifosz / 2 - 1) & 0xffff, devpriv->las0 + LAS0_ACNT); 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) { - /* this may generate un-sustainable interrupt rates */ - /* the application is responsible for doing the right thing */ - devpriv->transCount = cmd->chanlist_len; + /* + * this may generate un-sustainable interrupt rates + * the application is responsible for doing the + * right thing + */ + devpriv->xfer_count = cmd->chanlist_len; devpriv->flags |= SEND_EOS; } else { /* arrange to transfer data periodically */ - devpriv->transCount - = + devpriv->xfer_count = (TRANS_TARGET_PERIOD * cmd->chanlist_len) / cmd->scan_begin_arg; - if (devpriv->transCount < cmd->chanlist_len) { - /* tranfer after each scan (and avoid 0) */ - devpriv->transCount = cmd->chanlist_len; + if (devpriv->xfer_count < cmd->chanlist_len) { + /* transfer after each scan (and avoid 0) */ + devpriv->xfer_count = cmd->chanlist_len; } else { /* make a multiple of scan length */ - devpriv->transCount = - (devpriv->transCount + + devpriv->xfer_count = + (devpriv->xfer_count + cmd->chanlist_len - 1) / cmd->chanlist_len; - devpriv->transCount *= cmd->chanlist_len; + devpriv->xfer_count *= cmd->chanlist_len; } devpriv->flags |= SEND_EOS; } - if (devpriv->transCount >= (devpriv->fifoLen / 2)) { + if (devpriv->xfer_count >= (devpriv->fifosz / 2)) { /* out of counter range, use 1/2 fifo instead */ - devpriv->transCount = 0; + devpriv->xfer_count = 0; devpriv->flags &= ~SEND_EOS; } else { - /* interrupt for each tranfer */ - RtdAboutCounter(dev, devpriv->transCount - 1); + /* interrupt for each transfer */ + writel((devpriv->xfer_count - 1) & 0xffff, + devpriv->las0 + LAS0_ACNT); } - - DPRINTK - ("rtd520: scanLen=%d tranferCount=%d fifoLen=%d\n scanTime(ns)=%d flags=0x%x\n", - cmd->chanlist_len, devpriv->transCount, devpriv->fifoLen, - cmd->scan_begin_arg, devpriv->flags); } else { /* unknown timing, just use 1/2 FIFO */ - devpriv->transCount = 0; + devpriv->xfer_count = 0; devpriv->flags &= ~SEND_EOS; } - RtdPacerClockSource(dev, 1); /* use INTERNAL 8Mhz clock source */ - RtdAboutStopEnable(dev, 1); /* just interrupt, dont stop */ + /* pacer clock source: INTERNAL 8MHz */ + writel(1, devpriv->las0 + LAS0_PACER_SELECT); + /* just interrupt, don't stop */ + writel(1, devpriv->las0 + LAS0_ACNT_STOP_ENABLE); /* BUG??? these look like enumerated values, but they are bit fields */ /* First, setup when to stop */ switch (cmd->stop_src) { case TRIG_COUNT: /* stop after N scans */ - devpriv->aiCount = cmd->stop_arg * cmd->chanlist_len; - if ((devpriv->transCount > 0) - && (devpriv->transCount > devpriv->aiCount)) { - devpriv->transCount = devpriv->aiCount; + devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len; + if ((devpriv->xfer_count > 0) + && (devpriv->xfer_count > devpriv->ai_count)) { + devpriv->xfer_count = devpriv->ai_count; } break; case TRIG_NONE: /* stop when cancel is called */ - devpriv->aiCount = -1; /* read forever */ + devpriv->ai_count = -1; /* read forever */ break; - - default: - DPRINTK("rtd520: Warning! ignoring stop_src mode %d\n", - cmd->stop_src); } /* Scan timing */ @@ -2043,79 +1027,51 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) timer = rtd_ns_to_timer(&cmd->scan_begin_arg, TRIG_ROUND_NEAREST); /* set PACER clock */ - /*DPRINTK ("rtd520: loading %d into pacer\n", timer); */ - RtdPacerCounter(dev, timer); + writel(timer & 0xffffff, devpriv->las0 + LAS0_PCLK); break; case TRIG_EXT: - RtdPacerStartSource(dev, 1); /* EXTERNALy trigger pacer */ + /* pacer start source: EXTERNAL */ + writel(1, devpriv->las0 + LAS0_PACER_START); break; - - default: - DPRINTK("rtd520: Warning! ignoring scan_begin_src mode %d\n", - cmd->scan_begin_src); } /* Sample timing within a scan */ switch (cmd->convert_src) { case TRIG_TIMER: /* periodic */ - if (cmd->chanlist_len > 1) { /* only needed for multi-channel */ + if (cmd->chanlist_len > 1) { + /* only needed for multi-channel */ timer = rtd_ns_to_timer(&cmd->convert_arg, TRIG_ROUND_NEAREST); /* setup BURST clock */ - /*DPRINTK ("rtd520: loading %d into burst\n", timer); */ - RtdBurstCounter(dev, timer); + writel(timer & 0x3ff, devpriv->las0 + LAS0_BCLK); } break; case TRIG_EXT: /* external */ - RtdBurstStartSource(dev, 2); /* EXTERNALy trigger burst */ + /* burst trigger source: EXTERNAL */ + writel(2, devpriv->las0 + LAS0_BURST_START); break; - - default: - DPRINTK("rtd520: Warning! ignoring convert_src mode %d\n", - cmd->convert_src); } /* end configuration */ /* This doesn't seem to work. There is no way to clear an interrupt that the priority controller has queued! */ - RtdInterruptClearMask(dev, ~0); /* clear any existing flags */ - RtdInterruptClear(dev); + writew(~0, devpriv->las0 + LAS0_CLEAR); + readw(devpriv->las0 + LAS0_CLEAR); /* TODO: allow multiple interrupt sources */ - if (devpriv->transCount > 0) { /* transfer every N samples */ - RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT); - DPRINTK("rtd520: Transferring every %d\n", devpriv->transCount); + if (devpriv->xfer_count > 0) { /* transfer every N samples */ + writew(IRQM_ADC_ABOUT_CNT, devpriv->las0 + LAS0_IT); } else { /* 1/2 FIFO transfers */ -#ifdef USE_DMA - devpriv->flags |= DMA0_ACTIVE; - - /* point to first transfer in ring */ - devpriv->dma0Offset = 0; - RtdDma0Mode(dev, DMA_MODE_BITS); - RtdDma0Next(dev, /* point to first block */ - devpriv->dma0Chain[DMA_CHAIN_COUNT - 1].next); - RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL); /* set DMA trigger source */ - - RtdPlxInterruptWrite(dev, /* enable interrupt */ - RtdPlxInterruptRead(dev) | ICS_DMA0_E); - /* Must be 2 steps. See PLX app note about "Starting a DMA transfer" */ - RtdDma0Control(dev, PLX_DMA_EN_BIT); /* enable DMA (clear INTR?) */ - RtdDma0Control(dev, PLX_DMA_EN_BIT | PLX_DMA_START_BIT); /*start DMA */ - DPRINTK("rtd520: Using DMA0 transfers. plxInt %x RtdInt %x\n", - RtdPlxInterruptRead(dev), devpriv->intMask); -#else /* USE_DMA */ - RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT); - DPRINTK("rtd520: Transferring every 1/2 FIFO\n"); -#endif /* USE_DMA */ + writew(IRQM_ADC_ABOUT_CNT, devpriv->las0 + LAS0_IT); } /* BUG: start_src is ASSUMED to be TRIG_NOW */ /* BUG? it seems like things are running before the "start" */ - RtdPacerStart(dev); /* Start PACER */ + readl(devpriv->las0 + LAS0_PACER); /* start pacer */ return 0; } @@ -2124,92 +1080,55 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) */ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct rtd_private *devpriv = dev->private; + u32 overrun; u16 status; - RtdPacerStopSource(dev, 0); /* stop on SOFTWARE stop */ - RtdPacerStop(dev); /* Stop PACER */ - RtdAdcConversionSource(dev, 0); /* software trigger only */ - RtdInterruptMask(dev, 0); - devpriv->aiCount = 0; /* stop and don't transfer any more */ -#ifdef USE_DMA - if (devpriv->flags & DMA0_ACTIVE) { - RtdPlxInterruptWrite(dev, /* disable any more interrupts */ - RtdPlxInterruptRead(dev) & ~ICS_DMA0_E); - abort_dma(dev, 0); - devpriv->flags &= ~DMA0_ACTIVE; - } -#endif /* USE_DMA */ - status = RtdInterruptStatus(dev); - DPRINTK - ("rtd520: Acquisition canceled. %ld ints, intStat=%x, overStat=%x\n", - devpriv->intCount, status, - 0xffff & RtdInterruptOverrunStatus(dev)); + /* pacer stop source: SOFTWARE */ + writel(0, devpriv->las0 + LAS0_PACER_STOP); + writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */ + writel(0, devpriv->las0 + LAS0_ADC_CONVERSION); + writew(0, devpriv->las0 + LAS0_IT); + devpriv->ai_count = 0; /* stop and don't transfer any more */ + status = readw(devpriv->las0 + LAS0_IT); + overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff; return 0; } -/* - Given a desired period and the clock period (both in ns), - return the proper counter value (divider-1). - Sets the original period to be the true value. - Note: you have to check if the value is larger than the counter range! -*/ -static int rtd_ns_to_timer_base(unsigned int *nanosec, /* desired period (in ns) */ - int round_mode, int base) -{ /* clock period (in ns) */ - int divider; - - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - divider = (*nanosec + base / 2) / base; - break; - case TRIG_ROUND_DOWN: - divider = (*nanosec) / base; - break; - case TRIG_ROUND_UP: - divider = (*nanosec + base - 1) / base; - break; - } - if (divider < 2) - divider = 2; /* min is divide by 2 */ - - /* Note: we don't check for max, because different timers - have different ranges */ - - *nanosec = base * divider; - return divider - 1; /* countdown is divisor+1 */ -} - -/* - Given a desired period (in ns), - return the proper counter value (divider-1) for the internal clock. - Sets the original period to be the true value. -*/ -static int rtd_ns_to_timer(unsigned int *ns, int round_mode) +static int rtd_ao_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - return rtd_ns_to_timer_base(ns, round_mode, RTD_CLOCK_BASE); + struct rtd_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int bit = (chan == 0) ? FS_DAC1_NOT_EMPTY : FS_DAC2_NOT_EMPTY; + unsigned int status; + + status = readl(devpriv->las0 + LAS0_ADC); + if (status & bit) + return 0; + return -EBUSY; } -/* - Output one (or more) analog values to a single port as fast as possible. -*/ static int rtd_ao_winsn(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); int range = CR_RANGE(insn->chanspec); + int ret; /* Configure the output range (table index matches the range values) */ - RtdDacRange(dev, chan, range); + writew(range & 7, devpriv->las0 + + ((chan == 0) ? LAS0_DAC1_CTRL : LAS0_DAC2_CTRL)); /* 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) { int val = data[i] << 3; - int stat = 0; /* initialize to avoid bogus warning */ - int ii; /* VERIFY: comedi range and offset conversions */ @@ -2221,30 +1140,17 @@ static int rtd_ao_winsn(struct comedi_device *dev, val = data[i] << 3; } - DPRINTK - ("comedi: rtd520 DAC chan=%d range=%d writing %d as 0x%x\n", - chan, range, data[i], val); - /* a typical programming sequence */ - RtdDacFifoPut(dev, chan, val); /* put the value in */ - RtdDacUpdate(dev, chan); /* trigger the conversion */ - - devpriv->aoValue[chan] = data[i]; /* save for read back */ - - for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) { - stat = RtdFifoStatus(dev); - /* 1 -> not empty */ - if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY : - FS_DAC2_NOT_EMPTY)) - break; - WAIT_QUIETLY; - } - if (ii >= RTD_DAC_TIMEOUT) { - DPRINTK - ("rtd520: Error: DAC never finished! FifoStatus=0x%x\n", - stat ^ 0x6666); - return -ETIMEDOUT; - } + writew(val, devpriv->las1 + + ((chan == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO)); + writew(0, devpriv->las0 + + ((chan == 0) ? LAS0_DAC1 : LAS0_DAC2)); + + devpriv->ao_readback[chan] = data[i]; + + ret = comedi_timeout(dev, s, insn, rtd_ao_eoc, 0); + if (ret) + return ret; } /* return the number of samples read/written */ @@ -2257,134 +1163,263 @@ 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->aoValue[chan]; + data[i] = devpriv->ao_readback[chan]; return i; } -/* - Write a masked set of bits and the read back the port. - We track what the bits should be (i.e. we don't read the port first). - - 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 rtd_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; + struct rtd_private *devpriv = dev->private; - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - - /* Write out the new digital output lines */ - RtdDio0Write(dev, s->state); - } - /* on return, data[1] contains the value of the digital - * input lines. */ - data[1] = RtdDio0Read(dev); + if (comedi_dio_update_state(s, data)) + writew(s->state & 0xff, devpriv->las0 + LAS0_DIO0); - /*DPRINTK("rtd520:port_0 wrote: 0x%x read: 0x%x\n", s->state, data[1]); */ + data[1] = readw(devpriv->las0 + LAS0_DIO0) & 0xff; - return 2; + return insn->n; } -/* - Configure one bit on a IO port as Input or Output (hence the name :-). -*/ static int rtd_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + struct rtd_private *devpriv = dev->private; + int ret; - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << chan; /* 1 means Out */ - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << chan); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - } + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - DPRINTK("rtd520: port_0_direction=0x%x (1 means out)\n", s->io_bits); /* TODO support digital match interrupts and strobes */ - RtdDioStatusWrite(dev, 0x01); /* make Dio0Ctrl point to direction */ - RtdDio0CtrlWrite(dev, s->io_bits); /* set direction 1 means Out */ - RtdDioStatusWrite(dev, 0); /* make Dio0Ctrl clear interrupts */ + + /* set direction */ + writew(0x01, devpriv->las0 + LAS0_DIO_STATUS); + writew(s->io_bits & 0xff, devpriv->las0 + LAS0_DIO0_CTRL); + + /* clear interrupts */ + writew(0x00, devpriv->las0 + LAS0_DIO_STATUS); /* port1 can only be all input or all output */ /* there are also 2 user input lines and 2 user output lines */ - return 1; + return insn->n; +} + +static void rtd_reset(struct comedi_device *dev) +{ + struct rtd_private *devpriv = dev->private; + + writel(0, devpriv->las0 + LAS0_BOARD_RESET); + udelay(100); /* needed? */ + writel(0, devpriv->lcfg + PLX_INTRCS_REG); + writew(0, devpriv->las0 + LAS0_IT); + writew(~0, devpriv->las0 + LAS0_CLEAR); + readw(devpriv->las0 + LAS0_CLEAR); } /* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. + * initialize board, per RTD spec + * also, initialize shadow registers */ -static int __devinit rtd520Driver_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static void rtd_init_board(struct comedi_device *dev) { - return comedi_pci_auto_config(dev, rtd520Driver.driver_name); + struct rtd_private *devpriv = dev->private; + + rtd_reset(dev); + + writel(0, devpriv->las0 + LAS0_OVERRUN); + writel(0, devpriv->las0 + LAS0_CGT_CLEAR); + writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR); + writel(0, devpriv->las0 + LAS0_DAC1_RESET); + writel(0, devpriv->las0 + LAS0_DAC2_RESET); + /* clear digital IO fifo */ + writew(0, devpriv->las0 + LAS0_DIO_STATUS); + writeb((0 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL); + writeb((1 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL); + writeb((2 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL); + writeb((3 << 6) | 0x00, devpriv->las0 + LAS0_UTC_CTRL); + /* TODO: set user out source ??? */ } -static void __devexit rtd520Driver_pci_remove(struct pci_dev *dev) +/* The RTD driver does this */ +static void rtd_pci_latency_quirk(struct comedi_device *dev, + struct pci_dev *pcidev) { - comedi_pci_auto_unconfig(dev); + unsigned char pci_latency; + + pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency < 32) { + dev_info(dev->class_dev, + "PCI latency changed from %d to %d\n", + pci_latency, 32); + pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, 32); + } } -static struct pci_driver rtd520Driver_pci_driver = { - .id_table = rtd520_pci_table, - .probe = &rtd520Driver_pci_probe, - .remove = __devexit_p(&rtd520Driver_pci_remove) -}; - -static int __init rtd520Driver_init_module(void) +static int rtd_auto_attach(struct comedi_device *dev, + unsigned long context) { - int retval; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct rtd_boardinfo *board = NULL; + struct rtd_private *devpriv; + struct comedi_subdevice *s; + int ret; + + if (context < ARRAY_SIZE(rtd520Boards)) + board = &rtd520Boards[context]; + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + ret = comedi_pci_enable(dev); + if (ret) + return ret; + + devpriv->las0 = pci_ioremap_bar(pcidev, 2); + devpriv->las1 = pci_ioremap_bar(pcidev, 3); + devpriv->lcfg = pci_ioremap_bar(pcidev, 0); + if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg) + return -ENOMEM; + + rtd_pci_latency_quirk(dev, pcidev); + + if (pcidev->irq) { + ret = request_irq(pcidev->irq, rtd_interrupt, IRQF_SHARED, + dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; + } - retval = comedi_driver_register(&rtd520Driver); - if (retval < 0) - return retval; + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + s = &dev->subdevices[0]; + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->range_table = board->ai_range; + s->len_chanlist = RTD_MAX_CHANLIST; + s->insn_read = rtd_ai_rinsn; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->do_cmd = rtd_ai_cmd; + s->do_cmdtest = rtd_ai_cmdtest; + s->cancel = rtd_ai_cancel; + } + + s = &dev->subdevices[1]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 2; + s->maxdata = 0x0fff; + s->range_table = &rtd_ao_range; + s->insn_write = rtd_ao_winsn; + s->insn_read = rtd_ao_rinsn; + + s = &dev->subdevices[2]; + /* digital i/o subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + /* we only support port 0 right now. Ignoring port 1 and user IO */ + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = rtd_dio_insn_bits; + s->insn_config = rtd_dio_insn_config; + + /* timer/counter subdevices (not currently supported) */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 3; + s->maxdata = 0xffff; - rtd520Driver_pci_driver.name = (char *)rtd520Driver.driver_name; - return pci_register_driver(&rtd520Driver_pci_driver); + rtd_init_board(dev); + + ret = rtd520_probe_fifo_depth(dev); + if (ret < 0) + return ret; + devpriv->fifosz = ret; + + if (dev->irq) + writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG); + + return 0; } -static void __exit rtd520Driver_cleanup_module(void) +static void rtd_detach(struct comedi_device *dev) { - pci_unregister_driver(&rtd520Driver_pci_driver); - comedi_driver_unregister(&rtd520Driver); + struct rtd_private *devpriv = dev->private; + + if (devpriv) { + /* Shut down any board ops by resetting it */ + if (devpriv->las0 && devpriv->lcfg) + rtd_reset(dev); + if (dev->irq) { + writel(readl(devpriv->lcfg + PLX_INTRCS_REG) & + ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E), + devpriv->lcfg + PLX_INTRCS_REG); + free_irq(dev->irq, dev); + } + if (devpriv->las0) + iounmap(devpriv->las0); + if (devpriv->las1) + iounmap(devpriv->las1); + if (devpriv->lcfg) + iounmap(devpriv->lcfg); + } + comedi_pci_disable(dev); } -module_init(rtd520Driver_init_module); -module_exit(rtd520Driver_cleanup_module); +static struct comedi_driver rtd520_driver = { + .driver_name = "rtd520", + .module = THIS_MODULE, + .auto_attach = rtd_auto_attach, + .detach = rtd_detach, +}; + +static int rtd520_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + return comedi_pci_auto_config(dev, &rtd520_driver, id->driver_data); +} + +static const struct pci_device_id rtd520_pci_table[] = { + { PCI_VDEVICE(RTD, 0x7520), BOARD_DM7520 }, + { PCI_VDEVICE(RTD, 0x4520), BOARD_PCI4520 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, rtd520_pci_table); + +static struct pci_driver rtd520_pci_driver = { + .name = "rtd520", + .id_table = rtd520_pci_table, + .probe = rtd520_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(rtd520_driver, rtd520_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/rtd520.h b/drivers/staging/comedi/drivers/rtd520.h deleted file mode 100644 index a3ec2599c4b..00000000000 --- a/drivers/staging/comedi/drivers/rtd520.h +++ /dev/null @@ -1,412 +0,0 @@ -/* - comedi/drivers/rtd520.h - Comedi driver defines for Real Time Devices (RTD) PCI4520/DM7520 - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2001 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -/* - Created by Dan Christian, NASA Ames Research Center. - See board notes in rtd520.c -*/ - -/* - LAS0 Runtime Area - Local Address Space 0 Offset Read Function Write Function -*/ -#define LAS0_SPARE_00 0x0000 /* - - */ -#define LAS0_SPARE_04 0x0004 /* - - */ -#define LAS0_USER_IO 0x0008 /* Read User Inputs Write User Outputs */ -#define LAS0_SPARE_0C 0x000C /* - - */ -#define LAS0_ADC 0x0010 /* Read FIFO Status Software A/D Start */ -#define LAS0_DAC1 0x0014 /* - Software D/A1 Update */ -#define LAS0_DAC2 0x0018 /* - Software D/A2 Update */ -#define LAS0_SPARE_1C 0x001C /* - - */ -#define LAS0_SPARE_20 0x0020 /* - - */ -#define LAS0_DAC 0x0024 /* - Software Simultaneous D/A1 and D/A2 Update */ -#define LAS0_PACER 0x0028 /* Software Pacer Start Software Pacer Stop */ -#define LAS0_TIMER 0x002C /* Read Timer Counters Status HDIN Software Trigger */ -#define LAS0_IT 0x0030 /* Read Interrupt Status Write Interrupt Enable Mask Register */ -#define LAS0_CLEAR 0x0034 /* Clear ITs set by Clear Mask Set Interrupt Clear Mask */ -#define LAS0_OVERRUN 0x0038 /* Read pending interrupts Clear Overrun Register */ -#define LAS0_SPARE_3C 0x003C /* - - */ - -/* - LAS0 Runtime Area Timer/Counter,Dig.IO - Name Local Address Function -*/ -#define LAS0_PCLK 0x0040 /* Pacer Clock value (24bit) Pacer Clock load (24bit) */ -#define LAS0_BCLK 0x0044 /* Burst Clock value (10bit) Burst Clock load (10bit) */ -#define LAS0_ADC_SCNT 0x0048 /* A/D Sample counter value (10bit) A/D Sample counter load (10bit) */ -#define LAS0_DAC1_UCNT 0x004C /* D/A1 Update counter value (10 bit) D/A1 Update counter load (10bit) */ -#define LAS0_DAC2_UCNT 0x0050 /* D/A2 Update counter value (10 bit) D/A2 Update counter load (10bit) */ -#define LAS0_DCNT 0x0054 /* Delay counter value (16 bit) Delay counter load (16bit) */ -#define LAS0_ACNT 0x0058 /* About counter value (16 bit) About counter load (16bit) */ -#define LAS0_DAC_CLK 0x005C /* DAC clock value (16bit) DAC clock load (16bit) */ -#define LAS0_UTC0 0x0060 /* 8254 TC Counter 0 User TC 0 value Load count in TC Counter 0 */ -#define LAS0_UTC1 0x0064 /* 8254 TC Counter 1 User TC 1 value Load count in TC Counter 1 */ -#define LAS0_UTC2 0x0068 /* 8254 TC Counter 2 User TC 2 value Load count in TC Counter 2 */ -#define LAS0_UTC_CTRL 0x006C /* 8254 TC Control Word Program counter mode for TC */ -#define LAS0_DIO0 0x0070 /* Digital I/O Port 0 Read Port Digital I/O Port 0 Write Port */ -#define LAS0_DIO1 0x0074 /* Digital I/O Port 1 Read Port Digital I/O Port 1 Write Port */ -#define LAS0_DIO0_CTRL 0x0078 /* Clear digital IRQ status flag/read Clear digital chip/program Port 0 */ -#define LAS0_DIO_STATUS 0x007C /* Read Digital I/O Status word Program digital control register & */ - -/* - LAS0 Setup Area - Name Local Address Function -*/ -#define LAS0_BOARD_RESET 0x0100 /* Board reset */ -#define LAS0_DMA0_SRC 0x0104 /* DMA 0 Sources select */ -#define LAS0_DMA1_SRC 0x0108 /* DMA 1 Sources select */ -#define LAS0_ADC_CONVERSION 0x010C /* A/D Conversion Signal select */ -#define LAS0_BURST_START 0x0110 /* Burst Clock Start Trigger select */ -#define LAS0_PACER_START 0x0114 /* Pacer Clock Start Trigger select */ -#define LAS0_PACER_STOP 0x0118 /* Pacer Clock Stop Trigger select */ -#define LAS0_ACNT_STOP_ENABLE 0x011C /* About Counter Stop Enable */ -#define LAS0_PACER_REPEAT 0x0120 /* Pacer Start Trigger Mode select */ -#define LAS0_DIN_START 0x0124 /* High Speed Digital Input Sampling Signal select */ -#define LAS0_DIN_FIFO_CLEAR 0x0128 /* Digital Input FIFO Clear */ -#define LAS0_ADC_FIFO_CLEAR 0x012C /* A/D FIFO Clear */ -#define LAS0_CGT_WRITE 0x0130 /* Channel Gain Table Write */ -#define LAS0_CGL_WRITE 0x0134 /* Channel Gain Latch Write */ -#define LAS0_CG_DATA 0x0138 /* Digital Table Write */ -#define LAS0_CGT_ENABLE 0x013C /* Channel Gain Table Enable */ -#define LAS0_CG_ENABLE 0x0140 /* Digital Table Enable */ -#define LAS0_CGT_PAUSE 0x0144 /* Table Pause Enable */ -#define LAS0_CGT_RESET 0x0148 /* Reset Channel Gain Table */ -#define LAS0_CGT_CLEAR 0x014C /* Clear Channel Gain Table */ -#define LAS0_DAC1_CTRL 0x0150 /* D/A1 output type/range */ -#define LAS0_DAC1_SRC 0x0154 /* D/A1 update source */ -#define LAS0_DAC1_CYCLE 0x0158 /* D/A1 cycle mode */ -#define LAS0_DAC1_RESET 0x015C /* D/A1 FIFO reset */ -#define LAS0_DAC1_FIFO_CLEAR 0x0160 /* D/A1 FIFO clear */ -#define LAS0_DAC2_CTRL 0x0164 /* D/A2 output type/range */ -#define LAS0_DAC2_SRC 0x0168 /* D/A2 update source */ -#define LAS0_DAC2_CYCLE 0x016C /* D/A2 cycle mode */ -#define LAS0_DAC2_RESET 0x0170 /* D/A2 FIFO reset */ -#define LAS0_DAC2_FIFO_CLEAR 0x0174 /* D/A2 FIFO clear */ -#define LAS0_ADC_SCNT_SRC 0x0178 /* A/D Sample Counter Source select */ -#define LAS0_PACER_SELECT 0x0180 /* Pacer Clock select */ -#define LAS0_SBUS0_SRC 0x0184 /* SyncBus 0 Source select */ -#define LAS0_SBUS0_ENABLE 0x0188 /* SyncBus 0 enable */ -#define LAS0_SBUS1_SRC 0x018C /* SyncBus 1 Source select */ -#define LAS0_SBUS1_ENABLE 0x0190 /* SyncBus 1 enable */ -#define LAS0_SBUS2_SRC 0x0198 /* SyncBus 2 Source select */ -#define LAS0_SBUS2_ENABLE 0x019C /* SyncBus 2 enable */ -#define LAS0_ETRG_POLARITY 0x01A4 /* External Trigger polarity select */ -#define LAS0_EINT_POLARITY 0x01A8 /* External Interrupt polarity select */ -#define LAS0_UTC0_CLOCK 0x01AC /* UTC0 Clock select */ -#define LAS0_UTC0_GATE 0x01B0 /* UTC0 Gate select */ -#define LAS0_UTC1_CLOCK 0x01B4 /* UTC1 Clock select */ -#define LAS0_UTC1_GATE 0x01B8 /* UTC1 Gate select */ -#define LAS0_UTC2_CLOCK 0x01BC /* UTC2 Clock select */ -#define LAS0_UTC2_GATE 0x01C0 /* UTC2 Gate select */ -#define LAS0_UOUT0_SELECT 0x01C4 /* User Output 0 source select */ -#define LAS0_UOUT1_SELECT 0x01C8 /* User Output 1 source select */ -#define LAS0_DMA0_RESET 0x01CC /* DMA0 Request state machine reset */ -#define LAS0_DMA1_RESET 0x01D0 /* DMA1 Request state machine reset */ - -/* - LAS1 - Name Local Address Function -*/ -#define LAS1_ADC_FIFO 0x0000 /* Read A/D FIFO (16bit) - */ -#define LAS1_HDIO_FIFO 0x0004 /* Read High Speed Digital Input FIFO (16bit) - */ -#define LAS1_DAC1_FIFO 0x0008 /* - Write D/A1 FIFO (16bit) */ -#define LAS1_DAC2_FIFO 0x000C /* - Write D/A2 FIFO (16bit) */ - -/* - LCFG: PLX 9080 local config & runtime registers - Name Local Address Function -*/ -#define LCFG_ITCSR 0x0068 /* INTCSR, Interrupt Control/Status Register */ -#define LCFG_DMAMODE0 0x0080 /* DMA Channel 0 Mode Register */ -#define LCFG_DMAPADR0 0x0084 /* DMA Channel 0 PCI Address Register */ -#define LCFG_DMALADR0 0x0088 /* DMA Channel 0 Local Address Reg */ -#define LCFG_DMASIZ0 0x008C /* DMA Channel 0 Transfer Size (Bytes) Register */ -#define LCFG_DMADPR0 0x0090 /* DMA Channel 0 Descriptor Pointer Register */ -#define LCFG_DMAMODE1 0x0094 /* DMA Channel 1 Mode Register */ -#define LCFG_DMAPADR1 0x0098 /* DMA Channel 1 PCI Address Register */ -#define LCFG_DMALADR1 0x009C /* DMA Channel 1 Local Address Register */ -#define LCFG_DMASIZ1 0x00A0 /* DMA Channel 1 Transfer Size (Bytes) Register */ -#define LCFG_DMADPR1 0x00A4 /* DMA Channel 1 Descriptor Pointer Register */ -#define LCFG_DMACSR0 0x00A8 /* DMA Channel 0 Command/Status Register */ -#define LCFG_DMACSR1 0x00A9 /* DMA Channel 0 Command/Status Register */ -#define LCFG_DMAARB 0x00AC /* DMA Arbitration Register */ -#define LCFG_DMATHR 0x00B0 /* DMA Threshold Register */ - -/*====================================================================== - Resister bit definitions -======================================================================*/ - -/* FIFO Status Word Bits (RtdFifoStatus) */ -#define FS_DAC1_NOT_EMPTY 0x0001 /* D0 - DAC1 FIFO not empty */ -#define FS_DAC1_HEMPTY 0x0002 /* D1 - DAC1 FIFO half empty */ -#define FS_DAC1_NOT_FULL 0x0004 /* D2 - DAC1 FIFO not full */ -#define FS_DAC2_NOT_EMPTY 0x0010 /* D4 - DAC2 FIFO not empty */ -#define FS_DAC2_HEMPTY 0x0020 /* D5 - DAC2 FIFO half empty */ -#define FS_DAC2_NOT_FULL 0x0040 /* D6 - DAC2 FIFO not full */ -#define FS_ADC_NOT_EMPTY 0x0100 /* D8 - ADC FIFO not empty */ -#define FS_ADC_HEMPTY 0x0200 /* D9 - ADC FIFO half empty */ -#define FS_ADC_NOT_FULL 0x0400 /* D10 - ADC FIFO not full */ -#define FS_DIN_NOT_EMPTY 0x1000 /* D12 - DIN FIFO not empty */ -#define FS_DIN_HEMPTY 0x2000 /* D13 - DIN FIFO half empty */ -#define FS_DIN_NOT_FULL 0x4000 /* D14 - DIN FIFO not full */ - -/* Timer Status Word Bits (GetTimerStatus) */ -#define TS_PCLK_GATE 0x0001 -/* D0 - Pacer Clock Gate [0 - gated, 1 - enabled] */ -#define TS_BCLK_GATE 0x0002 -/* D1 - Burst Clock Gate [0 - disabled, 1 - running] */ -#define TS_DCNT_GATE 0x0004 -/* D2 - Pacer Clock Delayed Start Trigger [0 - delay over, 1 - delay in */ -/* progress] */ -#define TS_ACNT_GATE 0x0008 -/* D3 - Pacer Clock About Trigger [0 - completed, 1 - in progress] */ -#define TS_PCLK_RUN 0x0010 -/* D4 - Pacer Clock Shutdown Flag [0 - Pacer Clock cannot be start */ -/* triggered only by Software Pacer Start Command, 1 - Pacer Clock can */ -/* be start triggered] */ - -/* External Trigger polarity select */ -/* External Interrupt polarity select */ -#define POL_POSITIVE 0x0 /* positive edge */ -#define POL_NEGATIVE 0x1 /* negative edge */ - -/* User Output Signal select (SetUout0Source, SetUout1Source) */ -#define UOUT_ADC 0x0 /* A/D Conversion Signal */ -#define UOUT_DAC1 0x1 /* D/A1 Update */ -#define UOUT_DAC2 0x2 /* D/A2 Update */ -#define UOUT_SOFTWARE 0x3 /* Software Programmable */ - -/* Pacer clock select (SetPacerSource) */ -#define PCLK_INTERNAL 1 /* Internal Pacer Clock */ -#define PCLK_EXTERNAL 0 /* External Pacer Clock */ - -/* A/D Sample Counter Sources (SetAdcntSource, SetupSampleCounter) */ -#define ADC_SCNT_CGT_RESET 0x0 /* needs restart with StartPacer */ -#define ADC_SCNT_FIFO_WRITE 0x1 - -/* A/D Conversion Signal Select (for SetConversionSelect) */ -#define ADC_START_SOFTWARE 0x0 /* Software A/D Start */ -#define ADC_START_PCLK 0x1 /* Pacer Clock (Ext. Int. see Func.509) */ -#define ADC_START_BCLK 0x2 /* Burst Clock */ -#define ADC_START_DIGITAL_IT 0x3 /* Digital Interrupt */ -#define ADC_START_DAC1_MARKER1 0x4 /* D/A 1 Data Marker 1 */ -#define ADC_START_DAC2_MARKER1 0x5 /* D/A 2 Data Marker 1 */ -#define ADC_START_SBUS0 0x6 /* SyncBus 0 */ -#define ADC_START_SBUS1 0x7 /* SyncBus 1 */ -#define ADC_START_SBUS2 0x8 /* SyncBus 2 */ - -/* Burst Clock start trigger select (SetBurstStart) */ -#define BCLK_START_SOFTWARE 0x0 /* Software A/D Start (StartBurst) */ -#define BCLK_START_PCLK 0x1 /* Pacer Clock */ -#define BCLK_START_ETRIG 0x2 /* External Trigger */ -#define BCLK_START_DIGITAL_IT 0x3 /* Digital Interrupt */ -#define BCLK_START_SBUS0 0x4 /* SyncBus 0 */ -#define BCLK_START_SBUS1 0x5 /* SyncBus 1 */ -#define BCLK_START_SBUS2 0x6 /* SyncBus 2 */ - -/* Pacer Clock start trigger select (SetPacerStart) */ -#define PCLK_START_SOFTWARE 0x0 /* Software Pacer Start (StartPacer) */ -#define PCLK_START_ETRIG 0x1 /* External trigger */ -#define PCLK_START_DIGITAL_IT 0x2 /* Digital interrupt */ -#define PCLK_START_UTC2 0x3 /* User TC 2 out */ -#define PCLK_START_SBUS0 0x4 /* SyncBus 0 */ -#define PCLK_START_SBUS1 0x5 /* SyncBus 1 */ -#define PCLK_START_SBUS2 0x6 /* SyncBus 2 */ -#define PCLK_START_D_SOFTWARE 0x8 /* Delayed Software Pacer Start */ -#define PCLK_START_D_ETRIG 0x9 /* Delayed external trigger */ -#define PCLK_START_D_DIGITAL_IT 0xA /* Delayed digital interrupt */ -#define PCLK_START_D_UTC2 0xB /* Delayed User TC 2 out */ -#define PCLK_START_D_SBUS0 0xC /* Delayed SyncBus 0 */ -#define PCLK_START_D_SBUS1 0xD /* Delayed SyncBus 1 */ -#define PCLK_START_D_SBUS2 0xE /* Delayed SyncBus 2 */ -#define PCLK_START_ETRIG_GATED 0xF /* External Trigger Gated controlled mode */ - -/* Pacer Clock Stop Trigger select (SetPacerStop) */ -#define PCLK_STOP_SOFTWARE 0x0 /* Software Pacer Stop (StopPacer) */ -#define PCLK_STOP_ETRIG 0x1 /* External Trigger */ -#define PCLK_STOP_DIGITAL_IT 0x2 /* Digital Interrupt */ -#define PCLK_STOP_ACNT 0x3 /* About Counter */ -#define PCLK_STOP_UTC2 0x4 /* User TC2 out */ -#define PCLK_STOP_SBUS0 0x5 /* SyncBus 0 */ -#define PCLK_STOP_SBUS1 0x6 /* SyncBus 1 */ -#define PCLK_STOP_SBUS2 0x7 /* SyncBus 2 */ -#define PCLK_STOP_A_SOFTWARE 0x8 /* About Software Pacer Stop */ -#define PCLK_STOP_A_ETRIG 0x9 /* About External Trigger */ -#define PCLK_STOP_A_DIGITAL_IT 0xA /* About Digital Interrupt */ -#define PCLK_STOP_A_UTC2 0xC /* About User TC2 out */ -#define PCLK_STOP_A_SBUS0 0xD /* About SyncBus 0 */ -#define PCLK_STOP_A_SBUS1 0xE /* About SyncBus 1 */ -#define PCLK_STOP_A_SBUS2 0xF /* About SyncBus 2 */ - -/* About Counter Stop Enable */ -#define ACNT_STOP 0x0 /* stop enable */ -#define ACNT_NO_STOP 0x1 /* stop disabled */ - -/* DAC update source (SetDAC1Start & SetDAC2Start) */ -#define DAC_START_SOFTWARE 0x0 /* Software Update */ -#define DAC_START_CGT 0x1 /* CGT controlled Update */ -#define DAC_START_DAC_CLK 0x2 /* D/A Clock */ -#define DAC_START_EPCLK 0x3 /* External Pacer Clock */ -#define DAC_START_SBUS0 0x4 /* SyncBus 0 */ -#define DAC_START_SBUS1 0x5 /* SyncBus 1 */ -#define DAC_START_SBUS2 0x6 /* SyncBus 2 */ - -/* DAC Cycle Mode (SetDAC1Cycle, SetDAC2Cycle, SetupDAC) */ -#define DAC_CYCLE_SINGLE 0x0 /* not cycle */ -#define DAC_CYCLE_MULTI 0x1 /* cycle */ - -/* 8254 Operation Modes (Set8254Mode, SetupTimerCounter) */ -#define M8254_EVENT_COUNTER 0 /* Event Counter */ -#define M8254_HW_ONE_SHOT 1 /* Hardware-Retriggerable One-Shot */ -#define M8254_RATE_GENERATOR 2 /* Rate Generator */ -#define M8254_SQUARE_WAVE 3 /* Square Wave Mode */ -#define M8254_SW_STROBE 4 /* Software Triggered Strobe */ -#define M8254_HW_STROBE 5 /* Hardware Triggered Strobe (Retriggerable) */ - -/* User Timer/Counter 0 Clock Select (SetUtc0Clock) */ -#define CUTC0_8MHZ 0x0 /* 8MHz */ -#define CUTC0_EXT_TC_CLOCK1 0x1 /* Ext. TC Clock 1 */ -#define CUTC0_EXT_TC_CLOCK2 0x2 /* Ext. TC Clock 2 */ -#define CUTC0_EXT_PCLK 0x3 /* Ext. Pacer Clock */ - -/* User Timer/Counter 1 Clock Select (SetUtc1Clock) */ -#define CUTC1_8MHZ 0x0 /* 8MHz */ -#define CUTC1_EXT_TC_CLOCK1 0x1 /* Ext. TC Clock 1 */ -#define CUTC1_EXT_TC_CLOCK2 0x2 /* Ext. TC Clock 2 */ -#define CUTC1_EXT_PCLK 0x3 /* Ext. Pacer Clock */ -#define CUTC1_UTC0_OUT 0x4 /* User Timer/Counter 0 out */ -#define CUTC1_DIN_SIGNAL 0x5 /* High-Speed Digital Input Sampling signal */ - -/* User Timer/Counter 2 Clock Select (SetUtc2Clock) */ -#define CUTC2_8MHZ 0x0 /* 8MHz */ -#define CUTC2_EXT_TC_CLOCK1 0x1 /* Ext. TC Clock 1 */ -#define CUTC2_EXT_TC_CLOCK2 0x2 /* Ext. TC Clock 2 */ -#define CUTC2_EXT_PCLK 0x3 /* Ext. Pacer Clock */ -#define CUTC2_UTC1_OUT 0x4 /* User Timer/Counter 1 out */ - -/* User Timer/Counter 0 Gate Select (SetUtc0Gate) */ -#define GUTC0_NOT_GATED 0x0 /* Not gated */ -#define GUTC0_GATED 0x1 /* Gated */ -#define GUTC0_EXT_TC_GATE1 0x2 /* Ext. TC Gate 1 */ -#define GUTC0_EXT_TC_GATE2 0x3 /* Ext. TC Gate 2 */ - -/* User Timer/Counter 1 Gate Select (SetUtc1Gate) */ -#define GUTC1_NOT_GATED 0x0 /* Not gated */ -#define GUTC1_GATED 0x1 /* Gated */ -#define GUTC1_EXT_TC_GATE1 0x2 /* Ext. TC Gate 1 */ -#define GUTC1_EXT_TC_GATE2 0x3 /* Ext. TC Gate 2 */ -#define GUTC1_UTC0_OUT 0x4 /* User Timer/Counter 0 out */ - -/* User Timer/Counter 2 Gate Select (SetUtc2Gate) */ -#define GUTC2_NOT_GATED 0x0 /* Not gated */ -#define GUTC2_GATED 0x1 /* Gated */ -#define GUTC2_EXT_TC_GATE1 0x2 /* Ext. TC Gate 1 */ -#define GUTC2_EXT_TC_GATE2 0x3 /* Ext. TC Gate 2 */ -#define GUTC2_UTC1_OUT 0x4 /* User Timer/Counter 1 out */ - -/* Interrupt Source Masks (SetITMask, ClearITMask, GetITStatus) */ -#define IRQM_ADC_FIFO_WRITE 0x0001 /* ADC FIFO Write */ -#define IRQM_CGT_RESET 0x0002 /* Reset CGT */ -#define IRQM_CGT_PAUSE 0x0008 /* Pause CGT */ -#define IRQM_ADC_ABOUT_CNT 0x0010 /* About Counter out */ -#define IRQM_ADC_DELAY_CNT 0x0020 /* Delay Counter out */ -#define IRQM_ADC_SAMPLE_CNT 0x0040 /* ADC Sample Counter */ -#define IRQM_DAC1_UCNT 0x0080 /* DAC1 Update Counter */ -#define IRQM_DAC2_UCNT 0x0100 /* DAC2 Update Counter */ -#define IRQM_UTC1 0x0200 /* User TC1 out */ -#define IRQM_UTC1_INV 0x0400 /* User TC1 out, inverted */ -#define IRQM_UTC2 0x0800 /* User TC2 out */ -#define IRQM_DIGITAL_IT 0x1000 /* Digital Interrupt */ -#define IRQM_EXTERNAL_IT 0x2000 /* External Interrupt */ -#define IRQM_ETRIG_RISING 0x4000 /* External Trigger rising-edge */ -#define IRQM_ETRIG_FALLING 0x8000 /* External Trigger falling-edge */ - -/* DMA Request Sources (LAS0) */ -#define DMAS_DISABLED 0x0 /* DMA Disabled */ -#define DMAS_ADC_SCNT 0x1 /* ADC Sample Counter */ -#define DMAS_DAC1_UCNT 0x2 /* D/A1 Update Counter */ -#define DMAS_DAC2_UCNT 0x3 /* D/A2 Update Counter */ -#define DMAS_UTC1 0x4 /* User TC1 out */ -#define DMAS_ADFIFO_HALF_FULL 0x8 /* A/D FIFO half full */ -#define DMAS_DAC1_FIFO_HALF_EMPTY 0x9 /* D/A1 FIFO half empty */ -#define DMAS_DAC2_FIFO_HALF_EMPTY 0xA /* D/A2 FIFO half empty */ - -/* DMA Local Addresses (0x40000000+LAS1 offset) */ -#define DMALADDR_ADC 0x40000000 /* A/D FIFO */ -#define DMALADDR_HDIN 0x40000004 /* High Speed Digital Input FIFO */ -#define DMALADDR_DAC1 0x40000008 /* D/A1 FIFO */ -#define DMALADDR_DAC2 0x4000000C /* D/A2 FIFO */ - -/* Port 0 compare modes (SetDIO0CompareMode) */ -#define DIO_MODE_EVENT 0 /* Event Mode */ -#define DIO_MODE_MATCH 1 /* Match Mode */ - -/* Digital Table Enable (Port 1 disable) */ -#define DTBL_DISABLE 0 /* Enable Digital Table */ -#define DTBL_ENABLE 1 /* Disable Digital Table */ - -/* Sampling Signal for High Speed Digital Input (SetHdinStart) */ -#define HDIN_SOFTWARE 0x0 /* Software Trigger */ -#define HDIN_ADC 0x1 /* A/D Conversion Signal */ -#define HDIN_UTC0 0x2 /* User TC out 0 */ -#define HDIN_UTC1 0x3 /* User TC out 1 */ -#define HDIN_UTC2 0x4 /* User TC out 2 */ -#define HDIN_EPCLK 0x5 /* External Pacer Clock */ -#define HDIN_ETRG 0x6 /* External Trigger */ - -/* Channel Gain Table / Channel Gain Latch */ -#define CSC_LATCH 0 /* Channel Gain Latch mode */ -#define CSC_CGT 1 /* Channel Gain Table mode */ - -/* Channel Gain Table Pause Enable */ -#define CGT_PAUSE_DISABLE 0 /* Channel Gain Table Pause Disable */ -#define CGT_PAUSE_ENABLE 1 /* Channel Gain Table Pause Enable */ - -/* DAC output type/range (p63) */ -#define AOUT_UNIP5 0 /* 0..+5 Volt */ -#define AOUT_UNIP10 1 /* 0..+10 Volt */ -#define AOUT_BIP5 2 /* -5..+5 Volt */ -#define AOUT_BIP10 3 /* -10..+10 Volt */ - -/* Ghannel Gain Table field definitions (p61) */ -/* Gain */ -#define GAIN1 0 -#define GAIN2 1 -#define GAIN4 2 -#define GAIN8 3 -#define GAIN16 4 -#define GAIN32 5 -#define GAIN64 6 -#define GAIN128 7 - -/* Input range/polarity */ -#define AIN_BIP5 0 /* -5..+5 Volt */ -#define AIN_BIP10 1 /* -10..+10 Volt */ -#define AIN_UNIP10 2 /* 0..+10 Volt */ - -/* non referenced single ended select bit */ -#define NRSE_AGND 0 /* AGND referenced SE input */ -#define NRSE_AINS 1 /* AIN SENSE referenced SE input */ - -/* single ended vs differential */ -#define GND_SE 0 /* Single-Ended */ -#define GND_DIFF 1 /* Differential */ diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index 72042b81831..bd447b2add7 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -1,220 +1,176 @@ /* - comedi/drivers/rti800.c - Hardware driver for Analog Devices RTI-800/815 board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - + * comedi/drivers/rti800.c + * Hardware driver for Analog Devices RTI-800/815 board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ + /* -Driver: rti800 -Description: Analog Devices RTI-800/815 -Author: ds -Status: unknown -Updated: Fri, 05 Sep 2008 14:50:44 +0100 -Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815) - -Configuration options: - [0] - I/O port base address - [1] - IRQ - [2] - A/D reference - 0 = differential - 1 = pseudodifferential (common) - 2 = single-ended - [3] - A/D range - 0 = [-10,10] - 1 = [-5,5] - 2 = [0,10] - [4] - A/D encoding - 0 = two's complement - 1 = straight binary - [5] - DAC 0 range - 0 = [-10,10] - 1 = [0,10] - [6] - DAC 0 encoding - 0 = two's complement - 1 = straight binary - [7] - DAC 1 range (same as DAC 0) - [8] - DAC 1 encoding (same as DAC 0) -*/ + * Driver: rti800 + * Description: Analog Devices RTI-800/815 + * Devices: (Analog Devices) RTI-800 [rti800] + * (Analog Devices) RTI-815 [rti815] + * Author: David A. Schleef <ds@schleef.org> + * Status: unknown + * Updated: Fri, 05 Sep 2008 14:50:44 +0100 + * + * Configuration options: + * [0] - I/O port base address + * [1] - IRQ (not supported / unused) + * [2] - A/D mux/reference (number of channels) + * 0 = differential + * 1 = pseudodifferential (common) + * 2 = single-ended + * [3] - A/D range + * 0 = [-10,10] + * 1 = [-5,5] + * 2 = [0,10] + * [4] - A/D encoding + * 0 = two's complement + * 1 = straight binary + * [5] - DAC 0 range + * 0 = [-10,10] + * 1 = [0,10] + * [6] - DAC 0 encoding + * 0 = two's complement + * 1 = straight binary + * [7] - DAC 1 range (same as DAC 0) + * [8] - DAC 1 encoding (same as DAC 0) + */ +#include <linux/module.h> +#include <linux/delay.h> #include <linux/interrupt.h> #include "../comedidev.h" -#include <linux/ioport.h> - -#define RTI800_SIZE 16 - -#define RTI800_CSR 0 -#define RTI800_MUXGAIN 1 -#define RTI800_CONVERT 2 -#define RTI800_ADCLO 3 -#define RTI800_ADCHI 4 -#define RTI800_DAC0LO 5 -#define RTI800_DAC0HI 6 -#define RTI800_DAC1LO 7 -#define RTI800_DAC1HI 8 -#define RTI800_CLRFLAGS 9 -#define RTI800_DI 10 -#define RTI800_DO 11 -#define RTI800_9513A_DATA 12 -#define RTI800_9513A_CNTRL 13 -#define RTI800_9513A_STATUS 13 - /* - * flags for CSR register + * Register map */ +#define RTI800_CSR 0x00 +#define RTI800_CSR_BUSY (1 << 7) +#define RTI800_CSR_DONE (1 << 6) +#define RTI800_CSR_OVERRUN (1 << 5) +#define RTI800_CSR_TCR (1 << 4) +#define RTI800_CSR_DMA_ENAB (1 << 3) +#define RTI800_CSR_INTR_TC (1 << 2) +#define RTI800_CSR_INTR_EC (1 << 1) +#define RTI800_CSR_INTR_OVRN (1 << 0) +#define RTI800_MUXGAIN 0x01 +#define RTI800_CONVERT 0x02 +#define RTI800_ADCLO 0x03 +#define RTI800_ADCHI 0x04 +#define RTI800_DAC0LO 0x05 +#define RTI800_DAC0HI 0x06 +#define RTI800_DAC1LO 0x07 +#define RTI800_DAC1HI 0x08 +#define RTI800_CLRFLAGS 0x09 +#define RTI800_DI 0x0a +#define RTI800_DO 0x0b +#define RTI800_9513A_DATA 0x0c +#define RTI800_9513A_CNTRL 0x0d +#define RTI800_9513A_STATUS 0x0d + +#define RTI800_IOSIZE 0x10 + +static const struct comedi_lrange range_rti800_ai_10_bipolar = { + 4, { + BIP_RANGE(10), + BIP_RANGE(1), + BIP_RANGE(0.1), + BIP_RANGE(0.02) + } +}; -#define RTI800_BUSY 0x80 -#define RTI800_DONE 0x40 -#define RTI800_OVERRUN 0x20 -#define RTI800_TCR 0x10 -#define RTI800_DMA_ENAB 0x08 -#define RTI800_INTR_TC 0x04 -#define RTI800_INTR_EC 0x02 -#define RTI800_INTR_OVRN 0x01 - -#define Am9513_8BITBUS - -#define Am9513_output_control(a) outb(a, dev->iobase+RTI800_9513A_CNTRL) -#define Am9513_output_data(a) outb(a, dev->iobase+RTI800_9513A_DATA) -#define Am9513_input_data() inb(dev->iobase+RTI800_9513A_DATA) -#define Am9513_input_status() inb(dev->iobase+RTI800_9513A_STATUS) - -#include "am9513.h" - -static const struct comedi_lrange range_rti800_ai_10_bipolar = { 4, { - BIP_RANGE - (10), - BIP_RANGE - (1), - BIP_RANGE - (0.1), - BIP_RANGE - (0.02) - } +static const struct comedi_lrange range_rti800_ai_5_bipolar = { + 4, { + BIP_RANGE(5), + BIP_RANGE(0.5), + BIP_RANGE(0.05), + BIP_RANGE(0.01) + } }; -static const struct comedi_lrange range_rti800_ai_5_bipolar = { 4, { - BIP_RANGE - (5), - BIP_RANGE - (0.5), - BIP_RANGE - (0.05), - BIP_RANGE - (0.01) - } +static const struct comedi_lrange range_rti800_ai_unipolar = { + 4, { + UNI_RANGE(10), + UNI_RANGE(1), + UNI_RANGE(0.1), + UNI_RANGE(0.02) + } }; -static const struct comedi_lrange range_rti800_ai_unipolar = { 4, { - UNI_RANGE - (10), - UNI_RANGE(1), - UNI_RANGE - (0.1), - UNI_RANGE - (0.02) - } +static const struct comedi_lrange *const rti800_ai_ranges[] = { + &range_rti800_ai_10_bipolar, + &range_rti800_ai_5_bipolar, + &range_rti800_ai_unipolar, }; -struct rti800_board { +static const struct comedi_lrange *const rti800_ao_ranges[] = { + &range_bipolar10, + &range_unipolar10, +}; +struct rti800_board { const char *name; int has_ao; }; -static const struct rti800_board boardtypes[] = { - {"rti800", 0}, - {"rti815", 1}, -}; - -#define this_board ((const struct rti800_board *)dev->board_ptr) - -static int rti800_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int rti800_detach(struct comedi_device *dev); -static struct comedi_driver driver_rti800 = { - .driver_name = "rti800", - .module = THIS_MODULE, - .attach = rti800_attach, - .detach = rti800_detach, - .num_names = ARRAY_SIZE(boardtypes), - .board_name = &boardtypes[0].name, - .offset = sizeof(struct rti800_board), +static const struct rti800_board rti800_boardtypes[] = { + { + .name = "rti800", + }, { + .name = "rti815", + .has_ao = 1, + }, }; -static int __init driver_rti800_init_module(void) -{ - return comedi_driver_register(&driver_rti800); -} - -static void __exit driver_rti800_cleanup_module(void) -{ - comedi_driver_unregister(&driver_rti800); -} - -module_init(driver_rti800_init_module); -module_exit(driver_rti800_cleanup_module); - -static irqreturn_t rti800_interrupt(int irq, void *dev); - struct rti800_private { - enum { - adc_diff, adc_pseudodiff, adc_singleended - } adc_mux; - enum { - adc_bipolar10, adc_bipolar5, adc_unipolar10 - } adc_range; - enum { - adc_2comp, adc_straight - } adc_coding; - enum { - dac_bipolar10, dac_unipolar10 - } dac0_range, dac1_range; - enum { - dac_2comp, dac_straight - } dac0_coding, dac1_coding; + bool adc_2comp; + bool dac_2comp[2]; const struct comedi_lrange *ao_range_type_list[2]; unsigned int ao_readback[2]; - int muxgain_bits; + unsigned char muxgain_bits; }; -#define devpriv ((struct rti800_private *)dev->private) - -#define RTI800_TIMEOUT 100 - -static irqreturn_t rti800_interrupt(int irq, void *dev) +static int rti800_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - return IRQ_HANDLED; -} + unsigned char status; -/* settling delay times in usec for different gains */ -static const int gaindelay[] = { 10, 20, 40, 80 }; + status = inb(dev->iobase + RTI800_CSR); + if (status & RTI800_CSR_OVERRUN) { + outb(0, dev->iobase + RTI800_CLRFLAGS); + return -EOVERFLOW; + } + if (status & RTI800_CSR_DONE) + return 0; + return -EBUSY; +} static int rti800_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int i, t; - int status; - int chan = CR_CHAN(insn->chanspec); - unsigned gain = CR_RANGE(insn->chanspec); - unsigned muxgain_bits; + struct rti800_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int gain = CR_RANGE(insn->chanspec); + unsigned char muxgain_bits; + int ret; + int i; inb(dev->iobase + RTI800_ADCHI); outb(0, dev->iobase + RTI800_CLRFLAGS); @@ -223,270 +179,200 @@ static int rti800_ai_insn_read(struct comedi_device *dev, if (muxgain_bits != devpriv->muxgain_bits) { devpriv->muxgain_bits = muxgain_bits; outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN); - /* without a delay here, the RTI_OVERRUN bit - * gets set, and you will have an error. */ + /* + * Without a delay here, the RTI_CSR_OVERRUN bit + * gets set, and you will have an error. + */ if (insn->n > 0) { - BUG_ON(gain >= ARRAY_SIZE(gaindelay)); - udelay(gaindelay[gain]); + int delay = (gain == 0) ? 10 : + (gain == 1) ? 20 : + (gain == 2) ? 40 : 80; + + udelay(delay); } } for (i = 0; i < insn->n; i++) { outb(0, dev->iobase + RTI800_CONVERT); - for (t = RTI800_TIMEOUT; t; t--) { - status = inb(dev->iobase + RTI800_CSR); - if (status & RTI800_OVERRUN) { - printk(KERN_WARNING "rti800: a/d overrun\n"); - outb(0, dev->iobase + RTI800_CLRFLAGS); - return -EIO; - } - if (status & RTI800_DONE) - break; - udelay(1); - } - if (t == 0) { - printk(KERN_WARNING "rti800: timeout\n"); - return -ETIME; - } + + ret = comedi_timeout(dev, s, insn, rti800_ai_eoc, 0); + if (ret) + return ret; + data[i] = inb(dev->iobase + RTI800_ADCLO); - data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8; + data[i] |= (inb(dev->iobase + RTI800_ADCHI) & 0xf) << 8; - if (devpriv->adc_coding == adc_2comp) + if (devpriv->adc_2comp) data[i] ^= 0x800; } - return i; + 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 comedi_insn *insn, + unsigned int *data) { + struct rti800_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); 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 rti800_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) { - int chan = CR_CHAN(insn->chanspec); - int d; + struct rti800_private *devpriv = dev->private; + 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++) { - devpriv->ao_readback[chan] = d = data[i]; - if (devpriv->dac0_coding == dac_2comp) - d ^= 0x800; - - outb(d & 0xff, - dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO)); - outb(d >> 8, - dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI)); + val = data[i]; + if (devpriv->dac_2comp[chan]) + val ^= 0x800; + + outb(val & 0xff, dev->iobase + reg_lo); + outb((val >> 8) & 0xff, dev->iobase + reg_hi); } - return i; + + devpriv->ao_readback[chan] = val; + + return insn->n; } static int rti800_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; data[1] = inb(dev->iobase + RTI800_DI); - return 2; + return insn->n; } static int rti800_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + if (comedi_dio_update_state(s, data)) { /* Outputs are inverted... */ outb(s->state ^ 0xff, dev->iobase + RTI800_DO); } data[1] = s->state; - return 2; + return insn->n; } -/* - options[0] - I/O port - options[1] - irq - options[2] - a/d mux - 0=differential, 1=pseudodiff, 2=single - options[3] - a/d range - 0=bipolar10, 1=bipolar5, 2=unipolar10 - options[4] - a/d coding - 0=2's comp, 1=straight binary - options[5] - dac0 range - 0=bipolar10, 1=unipolar10 - options[6] - dac0 coding - 0=2's comp, 1=straight binary - options[7] - dac1 range - options[8] - dac1 coding - */ - static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - unsigned int irq; - unsigned long iobase; - int ret; + const struct rti800_board *board = comedi_board(dev); + struct rti800_private *devpriv; struct comedi_subdevice *s; + int ret; - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: rti800: 0x%04lx\n", dev->minor, iobase); - if (!request_region(iobase, RTI800_SIZE, "rti800")) { - printk(KERN_WARNING "I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - -#ifdef DEBUG - printk(KERN_DEBUG "fingerprint=%x,%x,%x,%x,%x ", - inb(dev->iobase + 0), - inb(dev->iobase + 1), - inb(dev->iobase + 2), - inb(dev->iobase + 3), inb(dev->iobase + 4)); -#endif + ret = comedi_request_region(dev, it->options[0], RTI800_IOSIZE); + if (ret) + return ret; outb(0, dev->iobase + RTI800_CSR); inb(dev->iobase + RTI800_ADCHI); outb(0, dev->iobase + RTI800_CLRFLAGS); - irq = it->options[1]; - if (irq) { - printk(KERN_INFO "( irq = %u )\n", irq); - ret = request_irq(irq, rti800_interrupt, 0, "rti800", dev); - if (ret < 0) { - printk(KERN_WARNING " Failed to allocate IRQ\n"); - return ret; - } - dev->irq = irq; - } else { - printk(KERN_INFO "( no irq )\n"); - } - - dev->board_name = this_board->name; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - ret = alloc_subdevices(dev, 4); - if (ret < 0) - return ret; + devpriv->adc_2comp = (it->options[4] == 0); + devpriv->dac_2comp[0] = (it->options[6] == 0); + devpriv->dac_2comp[1] = (it->options[8] == 0); + /* invalid, forces the MUXGAIN register to be set when first used */ + devpriv->muxgain_bits = 0xff; - ret = alloc_private(dev, sizeof(struct rti800_private)); - if (ret < 0) + ret = comedi_alloc_subdevices(dev, 4); + if (ret) return ret; - devpriv->adc_mux = it->options[2]; - devpriv->adc_range = it->options[3]; - devpriv->adc_coding = it->options[4]; - devpriv->dac0_range = it->options[5]; - devpriv->dac0_coding = it->options[6]; - devpriv->dac1_range = it->options[7]; - devpriv->dac1_coding = it->options[8]; - devpriv->muxgain_bits = -1; - - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = (devpriv->adc_mux ? 16 : 8); - s->insn_read = rti800_ai_insn_read; - s->maxdata = 0xfff; - switch (devpriv->adc_range) { - case adc_bipolar10: - s->range_table = &range_rti800_ai_10_bipolar; - break; - case adc_bipolar5: - s->range_table = &range_rti800_ai_5_bipolar; - break; - case adc_unipolar10: - s->range_table = &range_rti800_ai_unipolar; - break; - } - - s++; - if (this_board->has_ao) { + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = (it->options[2] ? 16 : 8); + s->insn_read = rti800_ai_insn_read; + s->maxdata = 0x0fff; + s->range_table = (it->options[3] < ARRAY_SIZE(rti800_ai_ranges)) + ? rti800_ai_ranges[it->options[3]] + : &range_unknown; + + s = &dev->subdevices[1]; + if (board->has_ao) { /* ao subdevice (only on rti815) */ - 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 = 0xfff; + 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; - switch (devpriv->dac0_range) { - case dac_bipolar10: - devpriv->ao_range_type_list[0] = &range_bipolar10; - break; - case dac_unipolar10: - devpriv->ao_range_type_list[0] = &range_unipolar10; - break; - } - switch (devpriv->dac1_range) { - case dac_bipolar10: - devpriv->ao_range_type_list[1] = &range_bipolar10; - break; - case dac_unipolar10: - devpriv->ao_range_type_list[1] = &range_unipolar10; - break; - } + devpriv->ao_range_type_list[0] = + (it->options[5] < ARRAY_SIZE(rti800_ao_ranges)) + ? rti800_ao_ranges[it->options[5]] + : &range_unknown; + devpriv->ao_range_type_list[1] = + (it->options[7] < ARRAY_SIZE(rti800_ao_ranges)) + ? rti800_ao_ranges[it->options[7]] + : &range_unknown; } else { - s->type = COMEDI_SUBD_UNUSED; + s->type = COMEDI_SUBD_UNUSED; } - s++; + s = &dev->subdevices[2]; /* di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 8; - s->insn_bits = rti800_di_insn_bits; - s->maxdata = 1; - s->range_table = &range_digital; - - s++; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 8; + s->insn_bits = rti800_di_insn_bits; + s->maxdata = 1; + s->range_table = &range_digital; + + s = &dev->subdevices[3]; /* do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 8; - s->insn_bits = rti800_do_insn_bits; - s->maxdata = 1; - s->range_table = &range_digital; - -/* don't yet know how to deal with counter/timers */ -#if 0 - s++; - /* do */ - s->type = COMEDI_SUBD_TIMER; -#endif + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 8; + s->insn_bits = rti800_do_insn_bits; + s->maxdata = 1; + s->range_table = &range_digital; + + /* + * There is also an Am9513 timer on these boards. This subdevice + * is not currently supported. + */ return 0; } -static int rti800_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: rti800: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, RTI800_SIZE); - - if (dev->irq) - free_irq(dev->irq, dev); - - return 0; -} +static struct comedi_driver rti800_driver = { + .driver_name = "rti800", + .module = THIS_MODULE, + .attach = rti800_attach, + .detach = comedi_legacy_detach, + .num_names = ARRAY_SIZE(rti800_boardtypes), + .board_name = &rti800_boardtypes[0].name, + .offset = sizeof(struct rti800_board), +}; +module_comedi_driver(rti800_driver); +MODULE_DESCRIPTION("Comedi: RTI-800 Multifunction Analog/Digital board"); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index f59cb11590f..605a31d702e 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -1,74 +1,44 @@ /* - comedi/drivers/rti802.c - Hardware driver for Analog Devices RTI-802 board - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - + * rti802.c + * Comedi driver for Analog Devices RTI-802 board + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ + /* -Driver: rti802 -Description: Analog Devices RTI-802 -Author: Anders Blomdell <anders.blomdell@control.lth.se> -Devices: [Analog Devices] RTI-802 (rti802) -Status: works - -Configuration Options: - [0] - i/o base - [1] - unused - [2] - dac#0 0=two's comp, 1=straight - [3] - dac#0 0=bipolar, 1=unipolar - [4] - dac#1 ... - ... - [17] - dac#7 ... -*/ + * Driver: rti802 + * Description: Analog Devices RTI-802 + * Author: Anders Blomdell <anders.blomdell@control.lth.se> + * Devices: (Analog Devices) RTI-802 [rti802] + * Status: works + * + * Configuration Options: + * [0] - i/o base + * [1] - unused + * [2,4,6,8,10,12,14,16] - dac#[0-7] 0=two's comp, 1=straight + * [3,5,7,9,11,13,15,17] - dac#[0-7] 0=bipolar, 1=unipolar + */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> - -#define RTI802_SIZE 4 - -#define RTI802_SELECT 0 -#define RTI802_DATALOW 1 -#define RTI802_DATAHIGH 2 - -static int rti802_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int rti802_detach(struct comedi_device *dev); -static struct comedi_driver driver_rti802 = { - .driver_name = "rti802", - .module = THIS_MODULE, - .attach = rti802_attach, - .detach = rti802_detach, -}; - -static int __init driver_rti802_init_module(void) -{ - return comedi_driver_register(&driver_rti802); -} - -static void __exit driver_rti802_cleanup_module(void) -{ - comedi_driver_unregister(&driver_rti802); -} - -module_init(driver_rti802_init_module); -module_exit(driver_rti802_cleanup_module); +/* + * Register I/O map + */ +#define RTI802_SELECT 0x00 +#define RTI802_DATALOW 0x01 +#define RTI802_DATAHIGH 0x02 struct rti802_private { enum { @@ -78,90 +48,96 @@ struct rti802_private { unsigned int ao_readback[8]; }; -#define devpriv ((struct rti802_private *)dev->private) - static int rti802_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct rti802_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; for (i = 0; i < insn->n; i++) - data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; + data[i] = devpriv->ao_readback[chan]; - return i; + return insn->n; } static int rti802_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int i, d; - int chan = CR_CHAN(insn->chanspec); + 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++) { - d = devpriv->ao_readback[chan] = data[i]; + val = data[i]; + + devpriv->ao_readback[chan] = val; + + /* munge offset binary to two's complement if needed */ if (devpriv->dac_coding[chan] == dac_2comp) - d ^= 0x800; - outb(chan, dev->iobase + RTI802_SELECT); - outb(d & 0xff, dev->iobase + RTI802_DATALOW); - outb(d >> 8, dev->iobase + RTI802_DATAHIGH); + val = comedi_offset_munge(s, val); + + outb(val & 0xff, dev->iobase + RTI802_DATALOW); + outb((val >> 8) & 0xff, dev->iobase + RTI802_DATAHIGH); } - return i; + + return insn->n; } static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + struct rti802_private *devpriv; struct comedi_subdevice *s; int i; - unsigned long iobase; + int ret; - iobase = it->options[0]; - printk(KERN_INFO "comedi%d: rti802: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, RTI802_SIZE, "rti802")) { - printk(KERN_WARNING "I/O port conflict\n"); - return -EIO; - } - dev->iobase = iobase; - - dev->board_name = "rti802"; + ret = comedi_request_region(dev, it->options[0], 0x04); + if (ret) + return ret; - if (alloc_subdevices(dev, 1) < 0 - || alloc_private(dev, sizeof(struct rti802_private))) { + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - } - s = dev->subdevices; - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->maxdata = 0xfff; - s->n_chan = 8; - s->insn_read = rti802_ao_insn_read; - s->insn_write = rti802_ao_insn_write; + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; + + /* Analog Output subdevice */ + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->maxdata = 0xfff; + s->n_chan = 8; + s->insn_read = rti802_ao_insn_read; + s->insn_write = rti802_ao_insn_write; s->range_table_list = devpriv->range_type_list; for (i = 0; i < 8; i++) { devpriv->dac_coding[i] = (it->options[3 + 2 * i]) - ? (dac_straight) - : (dac_2comp); + ? (dac_straight) : (dac_2comp); devpriv->range_type_list[i] = (it->options[2 + 2 * i]) - ? &range_unipolar10 : &range_bipolar10; + ? &range_unipolar10 : &range_bipolar10; } return 0; } -static int rti802_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: rti802: remove\n", dev->minor); - - if (dev->iobase) - release_region(dev->iobase, RTI802_SIZE); - - return 0; -} +static struct comedi_driver rti802_driver = { + .driver_name = "rti802", + .module = THIS_MODULE, + .attach = rti802_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(rti802_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); +MODULE_DESCRIPTION("Comedi driver for Analog Devices RTI-802 board"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 2b34daedc3d..85d2b7a3c12 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: s526 @@ -41,8 +36,8 @@ comedi_config /dev/comedi0 s526 0x2C0,0x3 */ +#include <linux/module.h> #include "../comedidev.h" -#include <linux/ioport.h> #include <asm/byteorder.h> #define S526_SIZE 64 @@ -83,36 +78,6 @@ comedi_config /dev/comedi0 s526 0x2C0,0x3 #define REG_EED 0x32 #define REG_EEC 0x34 -static const int s526_ports[] = { - REG_TCR, - REG_WDC, - REG_DAC, - REG_ADC, - REG_ADD, - REG_DIO, - REG_IER, - REG_ISR, - REG_MSC, - REG_C0L, - REG_C0H, - REG_C0M, - REG_C0C, - REG_C1L, - REG_C1H, - REG_C1M, - REG_C1C, - REG_C2L, - REG_C2H, - REG_C2M, - REG_C2C, - REG_C3L, - REG_C3H, - REG_C3M, - REG_C3C, - REG_EED, - REG_EEC -}; - struct counter_mode_register_t { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned short coutSource:1; @@ -148,416 +113,48 @@ union cmReg { unsigned short value; }; -#define MAX_GPCT_CONFIG_DATA 6 - -/* Different Application Classes for GPCT Subdevices */ -/* The list is not exhaustive and needs discussion! */ -enum S526_GPCT_APP_CLASS { - CountingAndTimeMeasurement, - SinglePulseGeneration, - PulseTrainGeneration, - PositionMeasurement, - Miscellaneous -}; - -/* Config struct for different GPCT subdevice Application Classes and - their options -*/ -struct s526GPCTConfig { - enum S526_GPCT_APP_CLASS app; - int data[MAX_GPCT_CONFIG_DATA]; -}; - -/* - * 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. - */ -struct s526_board { - const char *name; - int gpct_chans; - int gpct_bits; - int ad_chans; - int ad_bits; - int da_chans; - int da_bits; - int have_dio; -}; - -static const struct s526_board s526_boards[] = { - { - .name = "s526", - .gpct_chans = 4, - .gpct_bits = 24, - .ad_chans = 8, - .ad_bits = 16, - .da_chans = 4, - .da_bits = 16, - .have_dio = 1, - } -}; - -#define ADDR_REG(reg) (dev->iobase + (reg)) -#define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8) - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct s526_board *)dev->board_ptr) - -/* 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 s526_private { - - int data; - - /* would be useful for a PCI device */ - struct pci_dev *pci_dev; - - /* Used for AO readback */ unsigned int ao_readback[2]; - - struct s526GPCTConfig s526_gpct_config[4]; - unsigned short s526_ai_config; -}; - -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct s526_private *)dev->private) - -/* - * 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 int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int s526_detach(struct comedi_device *dev); -static struct comedi_driver driver_s526 = { - .driver_name = "s526", - .module = THIS_MODULE, - .attach = s526_attach, - .detach = s526_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 s526_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 = &s526_boards[0].name, - .offset = sizeof(struct s526_board), - .num_names = ARRAY_SIZE(s526_boards), + unsigned int gpct_config[4]; + unsigned short ai_config; }; static int s526_gpct_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int s526_gpct_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_gpct_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data); -static int s526_ai_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s526_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct comedi_subdevice *s; - int iobase; - int i, n; -/* short value; */ -/* int subdev_channel = 0; */ - union cmReg cmReg; - - printk(KERN_INFO "comedi%d: s526: ", dev->minor); - - iobase = it->options[0]; - if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) { - comedi_error(dev, "I/O port conflict"); - return -EIO; - } - dev->iobase = iobase; - - printk("iobase=0x%lx\n", dev->iobase); - - /*** make it a little quieter, exw, 8/29/06 - for (i = 0; i < S526_NUM_PORTS; i++) { - printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), - inw(ADDR_REG(s526_ports[i]))); - } - ***/ - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_ptr = &s526_boards[0]; - - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct s526_private)) < 0) - return -ENOMEM; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - dev->n_subdevices = 4; - if (alloc_subdevices(dev, dev->n_subdevices) < 0) - return -ENOMEM; - - s = dev->subdevices + 0; - /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; - /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */ - s->n_chan = thisboard->gpct_chans; - s->maxdata = 0x00ffffff; /* 24 bit counter */ - s->insn_read = s526_gpct_rinsn; - s->insn_config = s526_gpct_insn_config; - s->insn_write = s526_gpct_winsn; - - /* Command are not implemented yet, however they are necessary to - allocate the necessary memory for the comedi_async struct (used - to trigger the GPCT in case of pulsegenerator function */ - /* s->do_cmd = s526_gpct_cmd; */ - /* s->do_cmdtest = s526_gpct_cmdtest; */ - /* s->cancel = s526_gpct_cancel; */ - - s = dev->subdevices + 1; - /* dev->read_subdev=s; */ - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - /* we support differential */ - s->subdev_flags = SDF_READABLE | SDF_DIFF; - /* channels 0 to 7 are the regular differential inputs */ - /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ - s->n_chan = 10; - s->maxdata = 0xffff; - s->range_table = &range_bipolar10; - s->len_chanlist = 16; /* This is the maximum chanlist length that - the board can handle */ - s->insn_read = s526_ai_rinsn; - s->insn_config = s526_ai_insn_config; - - s = dev->subdevices + 2; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - 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 = dev->subdevices + 3; - /* digital i/o subdevice */ - if (thisboard->have_dio) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = s526_dio_insn_bits; - s->insn_config = s526_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - printk(KERN_INFO "attached\n"); - - return 1; - -#if 0 - /* Example of Counter Application */ - /* One-shot (software trigger) */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 1; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */ - cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 2; /* Hardware */ - cmReg.reg.clockSource = 2; /* Internal */ - cmReg.reg.countDir = 1; /* Down */ - cmReg.reg.countDirCtrl = 1; /* Software */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - - outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - - /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - /* Reset RCAP (fires one-shot) */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; + unsigned int lo; + unsigned int hi; + int i; -#else + for (i = 0; i < insn->n; i++) { + /* Read the low word first */ + lo = inw(chan_iobase + REG_C0L) & 0xffff; + hi = inw(chan_iobase + REG_C0H) & 0xff; - /* Set Counter Mode Register */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 0; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ - cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ - cmReg.reg.clockSource = 3; /* x4 */ - cmReg.reg.countDir = 0; /* up */ - cmReg.reg.countDirCtrl = 0; /* quadrature */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - n = 0; - printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n", - cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - udelay(1000); - printk(KERN_INFO "Read back mode reg=0x%04x\n", - inw(ADDR_CHAN_REG(REG_C0M, n))); - - /* Load the pre-load register high word */ -/* value = (short) (0x55); */ -/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */ - - /* Load the pre-load register low word */ -/* value = (short)(0xaa55); */ -/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */ - - /* Write the Counter Control Register */ -/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */ - - /* Reset the counter if it is software preload */ - if (cmReg.reg.autoLoadResetRcap == 0) { - /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); - /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); + data[i] = (hi << 16) | lo; } - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - udelay(1000); - printk(KERN_INFO "Read back mode reg=0x%04x\n", - inw(ADDR_CHAN_REG(REG_C0M, n))); - -#endif - printk(KERN_INFO "Current registres:\n"); - - for (i = 0; i < S526_NUM_PORTS; i++) { - printk(KERN_INFO "0x%02lx: 0x%04x\n", - ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); - } - return 1; -} - -/* - * _detach is called to deconfigure a device. It should deallocate - * resources. - * This function is also called when _attach() fails, so it should be - * careful not to release resources that were not necessarily - * allocated by _attach(). dev->private and dev->subdevices are - * deallocated automatically by the core. - */ -static int s526_detach(struct comedi_device *dev) -{ - printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor); - - if (dev->iobase > 0) - release_region(dev->iobase, S526_IOSIZE); - - return 0; -} - -static int s526_gpct_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) -{ - int i; /* counts the Data */ - int counter_channel = CR_CHAN(insn->chanspec); - unsigned short datalow; - unsigned short datahigh; - - /* Check if (n > 0) */ - if (insn->n <= 0) { - printk(KERN_ERR "s526: INSN_READ: n should be > 0\n"); - return -EINVAL; - } - /* Read the low word first */ - for (i = 0; i < insn->n; i++) { - datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel)); - datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel)); - data[i] = (int)(datahigh & 0x00FF); - data[i] = (data[i] << 16) | (datalow & 0xFFFF); - /* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", - counter_channel, data[i], datahigh, datalow); */ - } - return i; + return insn->n; } static int s526_gpct_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ - int i; - short value; + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; + unsigned int val; union cmReg cmReg; - /* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", - subdev_channel); */ - - for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) { - devpriv->s526_gpct_config[subdev_channel].data[i] = - insn->data[i]; -/* printk("data[%d]=%x\n", i, insn->data[i]); */ - } - /* Check what type of Counter the user requested, data[0] contains */ /* the Application type */ - switch (insn->data[0]) { + switch (data[0]) { case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: /* data[0]: Application Type @@ -565,9 +162,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[2]: Pre-load Register Value data[3]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n"); - devpriv->s526_gpct_config[subdev_channel].app = - PositionMeasurement; + devpriv->gpct_config[chan] = data[0]; #if 0 /* Example of Counter Application */ @@ -584,34 +179,32 @@ static int s526_gpct_insn_config(struct comedi_device *dev, cmReg.reg.preloadRegSel = 0; /* PR0 */ cmReg.reg.reserved = 0; - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); - outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + outw(0x0001, chan_iobase + REG_C0H); + outw(0x3C68, chan_iobase + REG_C0L); /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x4000, chan_iobase + REG_C0C); /* Reset RCAP (fires one-shot) */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x0008, chan_iobase + REG_C0C); #endif #if 1 /* Set Counter Mode Register */ - cmReg.value = insn->data[1] & 0xFFFF; - -/* printk("s526: Counter Mode register=%x\n", cmReg.value); */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + cmReg.value = data[1] & 0xffff; + outw(cmReg.value, chan_iobase + REG_C0M); /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 - * outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + * outw(0x4000, chan_iobase + REG_C0C); */ } #else @@ -619,47 +212,47 @@ static int s526_gpct_insn_config(struct comedi_device *dev, cmReg.reg.countDirCtrl = 0; /* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */ - if (insn->data[1] == GPCT_X2) + if (data[1] == GPCT_X2) cmReg.reg.clockSource = 1; - else if (insn->data[1] == GPCT_X4) + else if (data[1] == GPCT_X4) cmReg.reg.clockSource = 2; else cmReg.reg.clockSource = 0; /* When to take into account the indexpulse: */ - /*if (insn->data[2] == GPCT_IndexPhaseLowLow) { - } else if (insn->data[2] == GPCT_IndexPhaseLowHigh) { - } else if (insn->data[2] == GPCT_IndexPhaseHighLow) { - } else if (insn->data[2] == GPCT_IndexPhaseHighHigh) { + /*if (data[2] == GPCT_IndexPhaseLowLow) { + } else if (data[2] == GPCT_IndexPhaseLowHigh) { + } else if (data[2] == GPCT_IndexPhaseHighLow) { + } else if (data[2] == GPCT_IndexPhaseHighHigh) { }*/ /* Take into account the index pulse? */ - if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX) + if (data[3] == GPCT_RESET_COUNTER_ON_INDEX) /* Auto load with INDEX^ */ cmReg.reg.autoLoadResetRcap = 4; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + cmReg.value = data[1] & 0xffff; + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[3] != 0) { - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[3]) { + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0C); } /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x4000, chan_iobase + REG_C0C); } #endif break; @@ -672,40 +265,38 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[3]: Pre-load Register 1 Value data[4]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n"); - devpriv->s526_gpct_config[subdev_channel].app = - SinglePulseGeneration; + devpriv->gpct_config[chan] = data[0]; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 0; /* PR0 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 0 high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 0 low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 1; /* PR1 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 1 high word */ - value = (short)((insn->data[3] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[3] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 1 low word */ - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[4] != 0) { - value = (short)(insn->data[4] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[4]) { + val = data[4] & 0xffff; + outw(val, chan_iobase + REG_C0C); } break; @@ -717,45 +308,42 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[3]: Pre-load Register 1 Value data[4]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n"); - devpriv->s526_gpct_config[subdev_channel].app = - PulseTrainGeneration; + devpriv->gpct_config[chan] = data[0]; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 0; /* PR0 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 0 high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 0 low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 1; /* PR1 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 1 high word */ - value = (short)((insn->data[3] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[3] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 1 low word */ - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[4] != 0) { - value = (short)(insn->data[4] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[4]) { + val = data[4] & 0xffff; + outw(val, chan_iobase + REG_C0C); } break; default: - printk(KERN_ERR "s526: unsupported GPCT_insn_config\n"); return -EINVAL; break; } @@ -764,65 +352,40 @@ static int s526_gpct_insn_config(struct comedi_device *dev, } static int s526_gpct_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ - short value; - union cmReg cmReg; + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; - printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n", - subdev_channel); - cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel)); - printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value); - /* Check what Application of Counter this channel is configured for */ - switch (devpriv->s526_gpct_config[subdev_channel].app) { - case PositionMeasurement: - printk(KERN_INFO "S526: INSN_WRITE: PM\n"); - outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, - subdev_channel)); - outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); - break; + inw(chan_iobase + REG_C0M); /* Is this read required? */ - case SinglePulseGeneration: - printk(KERN_INFO "S526: INSN_WRITE: SPG\n"); - outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, - subdev_channel)); - outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); - break; - - case PulseTrainGeneration: + /* Check what Application of Counter this channel is configured for */ + switch (devpriv->gpct_config[chan]) { + case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR: /* data[0] contains the PULSE_WIDTH data[1] contains the PULSE_PERIOD @pre PULSE_PERIOD > PULSE_WIDTH > 0 The above periods must be expressed as a multiple of the pulse frequency on the selected source */ - printk(KERN_INFO "S526: INSN_WRITE: PTG\n"); - if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) { - (devpriv->s526_gpct_config[subdev_channel]).data[0] = - insn->data[0]; - (devpriv->s526_gpct_config[subdev_channel]).data[1] = - insn->data[1]; - } else { - printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n", - insn->data[0], insn->data[1]); + if ((data[1] <= data[0]) || !data[0]) return -EINVAL; - } - value = (short)((*data >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - value = (short)(*data & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + /* Fall thru to write the PULSE_WIDTH */ + + case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: + case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR: + outw((data[0] >> 16) & 0xffff, chan_iobase + REG_C0H); + outw(data[0] & 0xffff, chan_iobase + REG_C0L); break; - default: /* Impossible */ - printk - ("s526: INSN_WRITE: Functionality %d not implemented yet\n", - devpriv->s526_gpct_config[subdev_channel].app); + + default: return -EINVAL; - break; } - /* return the number of samples written */ + return insn->n; } @@ -831,6 +394,7 @@ static int s526_ai_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct s526_private *devpriv = dev->private; int result = -EINVAL; if (insn->n < 1) @@ -846,62 +410,58 @@ static int s526_ai_insn_config(struct comedi_device *dev, * INSN_READ handler. */ /* Enable ADC interrupt */ - outw(ISR_ADC_DONE, ADDR_REG(REG_IER)); -/* printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); */ - devpriv->s526_ai_config = (data[0] & 0x3FF) << 5; + outw(ISR_ADC_DONE, dev->iobase + REG_IER); + devpriv->ai_config = (data[0] & 0x3ff) << 5; if (data[1] > 0) - devpriv->s526_ai_config |= 0x8000; /* set the delay */ + devpriv->ai_config |= 0x8000; /* set the delay */ - devpriv->s526_ai_config |= 0x0001; /* ADC start bit. */ + devpriv->ai_config |= 0x0001; /* ADC start bit */ return result; } -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ +static int s526_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + unsigned int status; + + status = inw(dev->iobase + REG_ISR); + if (status & ISR_ADC_DONE) + return 0; + return -EBUSY; +} + static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; - int chan = CR_CHAN(insn->chanspec); + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int n; unsigned short value; unsigned int d; - unsigned int status; + int ret; /* Set configured delay, enable channel for this channel only, * select "ADC read" channel, set "ADC start" bit. */ - value = (devpriv->s526_ai_config & 0x8000) | - ((1 << 5) << chan) | (chan << 1) | 0x0001; + value = (devpriv->ai_config & 0x8000) | + ((1 << 5) << chan) | (chan << 1) | 0x0001; /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ - outw(value, ADDR_REG(REG_ADC)); -/* printk("s526: Wrote 0x%04x to ADC\n", value); */ -/* printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); */ + outw(value, dev->iobase + REG_ADC); -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = inw(ADDR_REG(REG_ISR)); - if (status & ISR_ADC_DONE) { - outw(ISR_ADC_DONE, ADDR_REG(REG_ISR)); - break; - } - } - if (i == TIMEOUT) { - /* printk() should be used instead of printk() - * whenever the code can be called from real-time. */ - printk(KERN_ERR "s526: ADC(0x%04x) timeout\n", - inw(ADDR_REG(REG_ISR))); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, s526_ai_eoc, 0); + if (ret) + return ret; + + outw(ISR_ADC_DONE, dev->iobase + REG_ISR); /* read data */ - d = inw(ADDR_REG(REG_ADD)); -/* printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); */ + d = inw(dev->iobase + REG_ADD); /* munge data */ data[n] = d ^ 0x8000; @@ -914,40 +474,30 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i; - int chan = CR_CHAN(insn->chanspec); + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); unsigned short val; + int i; -/* printk("s526_ao_winsn\n"); */ val = chan << 1; -/* outw(val, dev->iobase + REG_DAC); */ - outw(val, ADDR_REG(REG_DAC)); + outw(val, dev->iobase + REG_DAC); - /* 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 */ - /* write the data to preload register - * outw(data[i], dev->iobase + REG_ADD); - */ - /* write the data to preload register */ - outw(data[i], ADDR_REG(REG_ADD)); + outw(data[i], dev->iobase + REG_ADD); devpriv->ao_readback[chan] = data[i]; -/* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */ - outw(val + 1, ADDR_REG(REG_DAC)); /*starts the D/A conversion.*/ + /* starts the D/A conversion */ + outw(val + 1, dev->iobase + REG_DAC); } - /* 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 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; - int chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[chan]; @@ -955,90 +505,123 @@ static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 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 s526_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; + if (comedi_dio_update_state(s, data)) + outw(s->state, dev->iobase + REG_DIO); - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - outw(s->state, ADDR_REG(REG_DIO)); - } - - /* on return, data[1] contains the value of the digital - * input and output lines. */ - data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */ - /* or we could just return the software copy of the output values if - * it was a purely digital output subdevice */ - /* data[1]=s->state & 0xFF; */ + data[1] = inw(dev->iobase + REG_DIO) & 0xff; - return 2; + return insn->n; } static int s526_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); - int group, mask; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + int ret; + + if (chan < 4) + mask = 0x0f; + else + mask = 0xf0; + + ret = comedi_dio_insn_config(dev, s, insn, data, mask); + if (ret) + return ret; + + /* bit 10/11 set the group 1/2's mode */ + if (s->io_bits & 0x0f) + s->state |= (1 << 10); + else + s->state &= ~(1 << 10); + if (s->io_bits & 0xf0) + s->state |= (1 << 11); + else + s->state &= ~(1 << 11); + + outw(s->state, dev->iobase + REG_DIO); - printk(KERN_INFO "S526 DIO insn_config\n"); + return insn->n; +} - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ +static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct s526_private *devpriv; + struct comedi_subdevice *s; + int ret; - group = chan >> 2; - mask = 0xF << (group << 2); - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - /* bit 10/11 set the group 1/2's mode */ - s->state |= 1 << (group + 10); - s->io_bits |= mask; - break; - case INSN_CONFIG_DIO_INPUT: - s->state &= ~(1 << (group + 10)); /* 1 is output, 0 is input. */ - s->io_bits &= ~mask; - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - default: - return -EINVAL; - } - outw(s->state, ADDR_REG(REG_DIO)); + ret = comedi_request_region(dev, it->options[0], S526_IOSIZE); + if (ret) + return ret; - return 1; -} + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; -/* - * A convenient macro that defines init_module() and cleanup_module(), - * as necessary. - */ -static int __init driver_s526_init_module(void) -{ - return comedi_driver_register(&driver_s526); -} + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; -static void __exit driver_s526_cleanup_module(void) -{ - comedi_driver_unregister(&driver_s526); + s = &dev->subdevices[0]; + /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; + s->n_chan = 4; + s->maxdata = 0x00ffffff; /* 24 bit counter */ + s->insn_read = s526_gpct_rinsn; + s->insn_config = s526_gpct_insn_config; + s->insn_write = s526_gpct_winsn; + + s = &dev->subdevices[1]; + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + /* channels 0 to 7 are the regular differential inputs */ + /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ + s->n_chan = 10; + s->maxdata = 0xffff; + s->range_table = &range_bipolar10; + s->len_chanlist = 16; + s->insn_read = s526_ai_rinsn; + s->insn_config = s526_ai_insn_config; + + s = &dev->subdevices[2]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + 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 = &dev->subdevices[3]; + /* digital i/o subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = s526_dio_insn_bits; + s->insn_config = s526_dio_insn_config; + + return 0; } -module_init(driver_s526_init_module); -module_exit(driver_s526_cleanup_module); +static struct comedi_driver s526_driver = { + .driver_name = "s526", + .module = THIS_MODULE, + .attach = s526_attach, + .detach = comedi_legacy_detach, +}; +module_comedi_driver(s526_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index 23fc64b9988..0838f8aa695 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -1,1702 +1,2022 @@ /* - comedi/drivers/s626.c - Sensoray s626 Comedi driver - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - Based on Sensoray Model 626 Linux driver Version 0.2 - Copyright (C) 2002-2004 Sensoray Co., Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * comedi/drivers/s626.c + * Sensoray s626 Comedi driver + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * Based on Sensoray Model 626 Linux driver Version 0.2 + * Copyright (C) 2002-2004 Sensoray Co., Inc. + * + * 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: s626 -Description: Sensoray 626 driver -Devices: [Sensoray] 626 (s626) -Authors: Gianluca Palli <gpalli@deis.unibo.it>, -Updated: Fri, 15 Feb 2008 10:28:42 +0000 -Status: experimental - -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. - -INSN_CONFIG instructions: - analog input: - none - - analog output: - none - - digital channel: - s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels - supported configuration options: - INSN_CONFIG_DIO_QUERY - COMEDI_INPUT - COMEDI_OUTPUT - - encoder: - Every channel must be configured before reading. - - Example code - - insn.insn=INSN_CONFIG; //configuration instruction - insn.n=1; //number of operation (must be 1) - insn.data=&initialvalue; //initial value loaded into encoder - //during configuration - insn.subdev=5; //encoder subdevice - insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel - //to configure - - comedi_do_insn(cf,&insn); //executing configuration -*/ + * Driver: s626 + * Description: Sensoray 626 driver + * Devices: [Sensoray] 626 (s626) + * Authors: Gianluca Palli <gpalli@deis.unibo.it>, + * Updated: Fri, 15 Feb 2008 10:28:42 +0000 + * Status: experimental + + * Configuration options: not applicable, uses PCI auto config + + * INSN_CONFIG instructions: + * analog input: + * none + * + * analog output: + * none + * + * digital channel: + * s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels + * supported configuration options: + * INSN_CONFIG_DIO_QUERY + * COMEDI_INPUT + * COMEDI_OUTPUT + * + * encoder: + * Every channel must be configured before reading. + * + * Example code + * + * insn.insn=INSN_CONFIG; //configuration instruction + * insn.n=1; //number of operation (must be 1) + * insn.data=&initialvalue; //initial value loaded into encoder + * //during configuration + * insn.subdev=5; //encoder subdevice + * insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); //encoder_channel + * //to configure + * + * comedi_do_insn(cf,&insn); //executing configuration + */ +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/pci.h> #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/types.h> #include "../comedidev.h" -#include "comedi_pci.h" - #include "comedi_fc.h" #include "s626.h" -MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>"); -MODULE_DESCRIPTION("Sensoray 626 Comedi driver module"); -MODULE_LICENSE("GPL"); +struct s626_buffer_dma { + dma_addr_t physical_base; + void *logical_base; +}; -struct s626_board { - const char *name; - int ai_chans; - int ai_bits; - int ao_chans; - int ao_bits; - int dio_chans; - int dio_banks; - int enc_chans; +struct s626_private { + void __iomem *mmio; + 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 */ + int ai_convert_count; /* conversion counter */ + unsigned int ai_convert_timer; /* time between conversion in + * units of the timer */ + uint16_t counter_int_enabs; /* counter interrupt enable mask + * for MISC2 register */ + uint8_t adc_items; /* number of items in ADC poll list */ + struct s626_buffer_dma rps_buf; /* DMA buffer used to hold ADC (RPS1) + * program */ + struct s626_buffer_dma ana_buf; /* DMA buffer used to receive ADC data + * and hold DAC data */ + uint32_t *dac_wbuf; /* pointer to logical adrs of DMA buffer + * used to hold DAC data */ + uint16_t dacpol; /* image of DAC polarity register */ + 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]; }; -static const struct s626_board s626_boards[] = { - { - .name = "s626", - .ai_chans = S626_ADC_CHANNELS, - .ai_bits = 14, - .ao_chans = S626_DAC_CHANNELS, - .ao_bits = 13, - .dio_chans = S626_DIO_CHANNELS, - .dio_banks = S626_DIO_BANKS, - .enc_chans = S626_ENCODER_CHANNELS, - } +/* COUNTER OBJECT ------------------------------------------------ */ +struct s626_enc_info { + /* Pointers to functions that differ for A and B counters: */ + /* Return clock enable. */ + uint16_t (*get_enable)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return interrupt source. */ + uint16_t (*get_int_src)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return preload trigger source. */ + uint16_t (*get_load_trig)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Return standardized operating mode. */ + uint16_t (*get_mode)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Generate soft index strobe. */ + void (*pulse_index)(struct comedi_device *dev, + const struct s626_enc_info *k); + /* Program clock enable. */ + void (*set_enable)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab); + /* Program interrupt source. */ + void (*set_int_src)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t int_source); + /* Program preload trigger source. */ + void (*set_load_trig)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig); + /* Program standardized operating mode. */ + void (*set_mode)(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src); + /* Reset event capture flags. */ + void (*reset_cap_flags)(struct comedi_device *dev, + const struct s626_enc_info *k); + + uint16_t my_cra; /* address of CRA register */ + uint16_t my_crb; /* address of CRB register */ + uint16_t my_latch_lsw; /* address of Latch least-significant-word + * register */ + uint16_t my_event_bits[4]; /* bit translations for IntSrc -->RDMISC2 */ }; -#define thisboard ((const struct s626_board *)dev->board_ptr) -#define PCI_VENDOR_ID_S626 0x1131 -#define PCI_DEVICE_ID_S626 0x7146 +/* Counter overflow/index event flag masks for RDMISC2. */ +#define S626_INDXMASK(C) (1 << (((C) > 2) ? ((C) * 2 - 1) : ((C) * 2 + 4))) +#define S626_OVERMASK(C) (1 << (((C) > 2) ? ((C) * 2 + 5) : ((C) * 2 + 10))) +#define S626_EVBITS(C) { 0, S626_OVERMASK(C), S626_INDXMASK(C), \ + S626_OVERMASK(C) | S626_INDXMASK(C) } /* - * For devices with vendor:device id == 0x1131:0x7146 you must specify - * also subvendor:subdevice ids, because otherwise it will conflict with - * Philips SAA7146 media/dvb based cards. + * Translation table to map IntSrc into equivalent RDMISC2 event flag bits. + * static const uint16_t s626_event_bits[][4] = + * { S626_EVBITS(0), S626_EVBITS(1), S626_EVBITS(2), S626_EVBITS(3), + * S626_EVBITS(4), S626_EVBITS(5) }; */ -static DEFINE_PCI_DEVICE_TABLE(s626_pci_table) = { - {PCI_VENDOR_ID_S626, PCI_DEVICE_ID_S626, 0x6000, 0x0272, 0, 0, 0}, - {0} -}; -MODULE_DEVICE_TABLE(pci, s626_pci_table); +/* + * Enable/disable a function or test status bit(s) that are accessed + * through Main Control Registers 1 or 2. + */ +static void s626_mc_enable(struct comedi_device *dev, + unsigned int cmd, unsigned int reg) +{ + struct s626_private *devpriv = dev->private; + unsigned int val = (cmd << 16) | cmd; -static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int s626_detach(struct comedi_device *dev); + mmiowb(); + writel(val, devpriv->mmio + reg); +} -static struct comedi_driver driver_s626 = { - .driver_name = "s626", - .module = THIS_MODULE, - .attach = s626_attach, - .detach = s626_detach, -}; +static void s626_mc_disable(struct comedi_device *dev, + unsigned int cmd, unsigned int reg) +{ + struct s626_private *devpriv = dev->private; -struct s626_private { - struct pci_dev *pdev; - void *base_addr; - int got_regions; - short allocatedBuf; - uint8_t ai_cmd_running; /* ai_cmd is running */ - uint8_t ai_continous; /* continous acquisition */ - int ai_sample_count; /* number of samples to acquire */ - unsigned int ai_sample_timer; - /* time between samples in units of the timer */ - int ai_convert_count; /* conversion counter */ - unsigned int ai_convert_timer; - /* time between conversion in units of the timer */ - uint16_t CounterIntEnabs; - /* Counter interrupt enable mask for MISC2 register. */ - uint8_t AdcItems; /* Number of items in ADC poll list. */ - struct bufferDMA RPSBuf; /* DMA buffer used to hold ADC (RPS1) program. */ - struct bufferDMA ANABuf; - /* DMA buffer used to receive ADC data and hold DAC data. */ - uint32_t *pDacWBuf; - /* Pointer to logical adrs of DMA buffer used to hold DAC data. */ - uint16_t Dacpol; /* Image of DAC polarity register. */ - uint8_t TrimSetpoint[12]; /* Images of TrimDAC setpoints */ - uint16_t ChargeEnabled; /* Image of MISC2 Battery */ - /* Charge Enabled (0 or WRMISC2_CHARGE_ENABLE). */ - uint16_t WDInterval; /* Image of MISC2 watchdog interval control bits. */ - uint32_t I2CAdrs; - /* I2C device address for onboard EEPROM (board rev dependent). */ - /* short I2Cards; */ - unsigned int ao_readback[S626_DAC_CHANNELS]; -}; + writel(cmd << 16 , devpriv->mmio + reg); + mmiowb(); +} -struct dio_private { - uint16_t RDDIn; - uint16_t WRDOut; - uint16_t RDEdgSel; - uint16_t WREdgSel; - uint16_t RDCapSel; - uint16_t WRCapSel; - uint16_t RDCapFlg; - uint16_t RDIntSel; - uint16_t WRIntSel; -}; +static bool s626_mc_test(struct comedi_device *dev, + unsigned int cmd, unsigned int reg) +{ + struct s626_private *devpriv = dev->private; + unsigned int val; -static struct dio_private dio_private_A = { - .RDDIn = LP_RDDINA, - .WRDOut = LP_WRDOUTA, - .RDEdgSel = LP_RDEDGSELA, - .WREdgSel = LP_WREDGSELA, - .RDCapSel = LP_RDCAPSELA, - .WRCapSel = LP_WRCAPSELA, - .RDCapFlg = LP_RDCAPFLGA, - .RDIntSel = LP_RDINTSELA, - .WRIntSel = LP_WRINTSELA, -}; + val = readl(devpriv->mmio + reg); -static struct dio_private dio_private_B = { - .RDDIn = LP_RDDINB, - .WRDOut = LP_WRDOUTB, - .RDEdgSel = LP_RDEDGSELB, - .WREdgSel = LP_WREDGSELB, - .RDCapSel = LP_RDCAPSELB, - .WRCapSel = LP_WRCAPSELB, - .RDCapFlg = LP_RDCAPFLGB, - .RDIntSel = LP_RDINTSELB, - .WRIntSel = LP_WRINTSELB, -}; + return (val & cmd) ? true : false; +} -static struct dio_private dio_private_C = { - .RDDIn = LP_RDDINC, - .WRDOut = LP_WRDOUTC, - .RDEdgSel = LP_RDEDGSELC, - .WREdgSel = LP_WREDGSELC, - .RDCapSel = LP_RDCAPSELC, - .WRCapSel = LP_WRCAPSELC, - .RDCapFlg = LP_RDCAPFLGC, - .RDIntSel = LP_RDINTSELC, - .WRIntSel = LP_WRINTSELC, -}; +#define S626_BUGFIX_STREG(REGADRS) ((REGADRS) - 4) -/* to group dio devices (48 bits mask and data are not allowed ???) -static struct dio_private *dio_private_word[]={ - &dio_private_A, - &dio_private_B, - &dio_private_C, -}; -*/ +/* Write a time slot control record to TSL2. */ +#define S626_VECTPORT(VECTNUM) (S626_P_TSL2 + ((VECTNUM) << 2)) -#define devpriv ((struct s626_private *)dev->private) -#define diopriv ((struct dio_private *)s->private) +static const struct comedi_lrange s626_range_table = { + 2, { + BIP_RANGE(5), + BIP_RANGE(10) + } +}; -static int __devinit driver_s626_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +/* + * Execute a DEBI transfer. This must be called from within a critical section. + */ +static void s626_debi_transfer(struct comedi_device *dev) { - return comedi_pci_auto_config(dev, driver_s626.driver_name); + struct s626_private *devpriv = dev->private; + static const int timeout = 10000; + int i; + + /* Initiate upload of shadow RAM to DEBI control register */ + s626_mc_enable(dev, S626_MC2_UPLD_DEBI, S626_P_MC2); + + /* + * Wait for completion of upload from shadow RAM to + * DEBI control register. + */ + for (i = 0; i < timeout; i++) { + if (s626_mc_test(dev, S626_MC2_UPLD_DEBI, S626_P_MC2)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, + "Timeout while uploading to DEBI control register."); + + /* Wait until DEBI transfer is done */ + for (i = 0; i < timeout; i++) { + if (!(readl(devpriv->mmio + S626_P_PSR) & S626_PSR_DEBI_S)) + break; + udelay(1); + } + if (i == timeout) + comedi_error(dev, "DEBI transfer timeout."); } -static void __devexit driver_s626_pci_remove(struct pci_dev *dev) +/* + * Read a value from a gate array register. + */ +static uint16_t s626_debi_read(struct comedi_device *dev, uint16_t addr) { - comedi_pci_auto_unconfig(dev); + struct s626_private *devpriv = dev->private; + + /* Set up DEBI control register value in shadow RAM */ + writel(S626_DEBI_CMD_RDWORD | addr, devpriv->mmio + S626_P_DEBICMD); + + /* Execute the DEBI transfer. */ + s626_debi_transfer(dev); + + return readl(devpriv->mmio + S626_P_DEBIAD); } -static struct pci_driver driver_s626_pci_driver = { - .id_table = s626_pci_table, - .probe = &driver_s626_pci_probe, - .remove = __devexit_p(&driver_s626_pci_remove) -}; +/* + * Write a value to a gate array register. + */ +static void s626_debi_write(struct comedi_device *dev, uint16_t addr, + uint16_t wdata) +{ + struct s626_private *devpriv = dev->private; + + /* Set up DEBI control register value in shadow RAM */ + writel(S626_DEBI_CMD_WRWORD | addr, devpriv->mmio + S626_P_DEBICMD); + writel(wdata, devpriv->mmio + S626_P_DEBIAD); + + /* Execute the DEBI transfer. */ + s626_debi_transfer(dev); +} -static int __init driver_s626_init_module(void) +/* + * Replace the specified bits in a gate array register. Imports: mask + * specifies bits that are to be preserved, wdata is new value to be + * or'd with the masked original. + */ +static void s626_debi_replace(struct comedi_device *dev, unsigned int addr, + unsigned int mask, unsigned int wdata) { - int retval; + struct s626_private *devpriv = dev->private; + unsigned int val; - retval = comedi_driver_register(&driver_s626); - if (retval < 0) - return retval; + addr &= 0xffff; + writel(S626_DEBI_CMD_RDWORD | addr, devpriv->mmio + S626_P_DEBICMD); + s626_debi_transfer(dev); - driver_s626_pci_driver.name = (char *)driver_s626.driver_name; - return pci_register_driver(&driver_s626_pci_driver); + writel(S626_DEBI_CMD_WRWORD | addr, devpriv->mmio + S626_P_DEBICMD); + val = readl(devpriv->mmio + S626_P_DEBIAD); + val &= mask; + val |= wdata; + writel(val & 0xffff, devpriv->mmio + S626_P_DEBIAD); + s626_debi_transfer(dev); } -static void __exit driver_s626_cleanup_module(void) +/* ************** EEPROM ACCESS FUNCTIONS ************** */ + +static int s626_i2c_handshake_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - pci_unregister_driver(&driver_s626_pci_driver); - comedi_driver_unregister(&driver_s626); + bool status; + + status = s626_mc_test(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + if (status) + return 0; + return -EBUSY; } -module_init(driver_s626_init_module); -module_exit(driver_s626_cleanup_module); +static int s626_i2c_handshake(struct comedi_device *dev, uint32_t val) +{ + struct s626_private *devpriv = dev->private; + unsigned int ctrl; + int ret; -/* ioctl routines */ -static int s626_ai_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -/* static int s626_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */ -static int s626_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s); -static int s626_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int s626_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s626_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s626_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan); -static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int gruop, - unsigned int mask); -static int s626_dio_clear_irq(struct comedi_device *dev); -static int s626_enc_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s626_enc_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s626_enc_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int s626_ns_to_timer(int *nanosec, int round_mode); -static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd); -static int s626_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum); -static irqreturn_t s626_irq_handler(int irq, void *d); -static unsigned int s626_ai_reg_to_uint(int data); -/* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data); */ - -/* end ioctl routines */ - -/* internal routines */ -static void s626_dio_init(struct comedi_device *dev); -static void ResetADC(struct comedi_device *dev, uint8_t * ppl); -static void LoadTrimDACs(struct comedi_device *dev); -static void WriteTrimDAC(struct comedi_device *dev, uint8_t LogicalChan, - uint8_t DacData); -static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr); -static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val); -static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata); -static void SendDAC(struct comedi_device *dev, uint32_t val); -static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage); -static void DEBItransfer(struct comedi_device *dev); -static uint16_t DEBIread(struct comedi_device *dev, uint16_t addr); -static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata); -static void DEBIreplace(struct comedi_device *dev, uint16_t addr, uint16_t mask, - uint16_t wdata); -static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma, - size_t bsize); - -/* COUNTER OBJECT ------------------------------------------------ */ -struct enc_private { - /* Pointers to functions that differ for A and B counters: */ - uint16_t(*GetEnable) (struct comedi_device *dev, struct enc_private *); /* Return clock enable. */ - uint16_t(*GetIntSrc) (struct comedi_device *dev, struct enc_private *); /* Return interrupt source. */ - uint16_t(*GetLoadTrig) (struct comedi_device *dev, struct enc_private *); /* Return preload trigger source. */ - uint16_t(*GetMode) (struct comedi_device *dev, struct enc_private *); /* Return standardized operating mode. */ - void (*PulseIndex) (struct comedi_device *dev, struct enc_private *); /* Generate soft index strobe. */ - void (*SetEnable) (struct comedi_device *dev, struct enc_private *, uint16_t enab); /* Program clock enable. */ - void (*SetIntSrc) (struct comedi_device *dev, struct enc_private *, uint16_t IntSource); /* Program interrupt source. */ - void (*SetLoadTrig) (struct comedi_device *dev, struct enc_private *, uint16_t Trig); /* Program preload trigger source. */ - void (*SetMode) (struct comedi_device *dev, struct enc_private *, uint16_t Setup, uint16_t DisableIntSrc); /* Program standardized operating mode. */ - void (*ResetCapFlags) (struct comedi_device *dev, struct enc_private *); /* Reset event capture flags. */ - - uint16_t MyCRA; /* Address of CRA register. */ - uint16_t MyCRB; /* Address of CRB register. */ - uint16_t MyLatchLsw; /* Address of Latch least-significant-word */ - /* register. */ - uint16_t MyEventBits[4]; /* Bit translations for IntSrc -->RDMISC2. */ -}; + /* Write I2C command to I2C Transfer Control shadow register */ + writel(val, devpriv->mmio + S626_P_I2CCTRL); -#define encpriv ((struct enc_private *)(dev->subdevices+5)->private) - -/* counters routines */ -static void s626_timer_load(struct comedi_device *dev, struct enc_private *k, - int tick); -static uint32_t ReadLatch(struct comedi_device *dev, struct enc_private *k); -static void ResetCapFlags_A(struct comedi_device *dev, struct enc_private *k); -static void ResetCapFlags_B(struct comedi_device *dev, struct enc_private *k); -static uint16_t GetMode_A(struct comedi_device *dev, struct enc_private *k); -static uint16_t GetMode_B(struct comedi_device *dev, struct enc_private *k); -static void SetMode_A(struct comedi_device *dev, struct enc_private *k, - uint16_t Setup, uint16_t DisableIntSrc); -static void SetMode_B(struct comedi_device *dev, struct enc_private *k, - uint16_t Setup, uint16_t DisableIntSrc); -static void SetEnable_A(struct comedi_device *dev, struct enc_private *k, - uint16_t enab); -static void SetEnable_B(struct comedi_device *dev, struct enc_private *k, - uint16_t enab); -static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k); -static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k); -static void SetLatchSource(struct comedi_device *dev, struct enc_private *k, - uint16_t value); -/* static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k ); */ -static void SetLoadTrig_A(struct comedi_device *dev, struct enc_private *k, - uint16_t Trig); -static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k, - uint16_t Trig); -static uint16_t GetLoadTrig_A(struct comedi_device *dev, struct enc_private *k); -static uint16_t GetLoadTrig_B(struct comedi_device *dev, struct enc_private *k); -static void SetIntSrc_B(struct comedi_device *dev, struct enc_private *k, - uint16_t IntSource); -static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k, - uint16_t IntSource); -static uint16_t GetIntSrc_A(struct comedi_device *dev, struct enc_private *k); -static uint16_t GetIntSrc_B(struct comedi_device *dev, struct enc_private *k); -/* static void SetClkMult(struct comedi_device *dev, struct enc_private *k, uint16_t value ) ; */ -/* static uint16_t GetClkMult(struct comedi_device *dev, struct enc_private *k ) ; */ -/* static void SetIndexPol(struct comedi_device *dev, struct enc_private *k, uint16_t value ); */ -/* static uint16_t GetClkPol(struct comedi_device *dev, struct enc_private *k ) ; */ -/* static void SetIndexSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value ); */ -/* static uint16_t GetClkSrc( struct comedi_device *dev,struct enc_private *k ); */ -/* static void SetIndexSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value ); */ -/* static uint16_t GetIndexSrc( struct comedi_device *dev,struct enc_private *k ); */ -static void PulseIndex_A(struct comedi_device *dev, struct enc_private *k); -static void PulseIndex_B(struct comedi_device *dev, struct enc_private *k); -static void Preload(struct comedi_device *dev, struct enc_private *k, - uint32_t value); -static void CountersInit(struct comedi_device *dev); -/* end internal routines */ - -/* Counter objects constructor. */ - -/* Counter overflow/index event flag masks for RDMISC2. */ -#define INDXMASK(C) (1 << (((C) > 2) ? ((C) * 2 - 1) : ((C) * 2 + 4))) -#define OVERMASK(C) (1 << (((C) > 2) ? ((C) * 2 + 5) : ((C) * 2 + 10))) -#define EVBITS(C) { 0, OVERMASK(C), INDXMASK(C), OVERMASK(C) | INDXMASK(C) } - -/* Translation table to map IntSrc into equivalent RDMISC2 event flag bits. */ -/* static const uint16_t EventBits[][4] = { EVBITS(0), EVBITS(1), EVBITS(2), EVBITS(3), EVBITS(4), EVBITS(5) }; */ - -/* struct enc_private; */ -static struct enc_private enc_private_data[] = { - { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR0A, - .MyCRB = LP_CR0B, - .MyLatchLsw = LP_CNTR0ALSW, - .MyEventBits = EVBITS(0), - }, - { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR1A, - .MyCRB = LP_CR1B, - .MyLatchLsw = LP_CNTR1ALSW, - .MyEventBits = EVBITS(1), - }, - { - .GetEnable = GetEnable_A, - .GetIntSrc = GetIntSrc_A, - .GetLoadTrig = GetLoadTrig_A, - .GetMode = GetMode_A, - .PulseIndex = PulseIndex_A, - .SetEnable = SetEnable_A, - .SetIntSrc = SetIntSrc_A, - .SetLoadTrig = SetLoadTrig_A, - .SetMode = SetMode_A, - .ResetCapFlags = ResetCapFlags_A, - .MyCRA = LP_CR2A, - .MyCRB = LP_CR2B, - .MyLatchLsw = LP_CNTR2ALSW, - .MyEventBits = EVBITS(2), - }, - { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR0A, - .MyCRB = LP_CR0B, - .MyLatchLsw = LP_CNTR0BLSW, - .MyEventBits = EVBITS(3), - }, - { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR1A, - .MyCRB = LP_CR1B, - .MyLatchLsw = LP_CNTR1BLSW, - .MyEventBits = EVBITS(4), - }, - { - .GetEnable = GetEnable_B, - .GetIntSrc = GetIntSrc_B, - .GetLoadTrig = GetLoadTrig_B, - .GetMode = GetMode_B, - .PulseIndex = PulseIndex_B, - .SetEnable = SetEnable_B, - .SetIntSrc = SetIntSrc_B, - .SetLoadTrig = SetLoadTrig_B, - .SetMode = SetMode_B, - .ResetCapFlags = ResetCapFlags_B, - .MyCRA = LP_CR2A, - .MyCRB = LP_CR2B, - .MyLatchLsw = LP_CNTR2BLSW, - .MyEventBits = EVBITS(5), - }, -}; + /* + * Upload I2C shadow registers into working registers and + * wait for upload confirmation. + */ + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; -/* enab/disable a function or test status bit(s) that are accessed */ -/* through Main Control Registers 1 or 2. */ -#define MC_ENABLE(REGADRS, CTRLWORD) writel(((uint32_t)(CTRLWORD) << 16) | (uint32_t)(CTRLWORD), devpriv->base_addr+(REGADRS)) + /* Wait until I2C bus transfer is finished or an error occurs */ + do { + ctrl = readl(devpriv->mmio + S626_P_I2CCTRL); + } while ((ctrl & (S626_I2C_BUSY | S626_I2C_ERR)) == S626_I2C_BUSY); -#define MC_DISABLE(REGADRS, CTRLWORD) writel((uint32_t)(CTRLWORD) << 16 , devpriv->base_addr+(REGADRS)) + /* Return non-zero if I2C error occurred */ + return ctrl & S626_I2C_ERR; +} -#define MC_TEST(REGADRS, CTRLWORD) ((readl(devpriv->base_addr+(REGADRS)) & CTRLWORD) != 0) +/* Read uint8_t from EEPROM. */ +static uint8_t s626_i2c_read(struct comedi_device *dev, uint8_t addr) +{ + struct s626_private *devpriv = dev->private; -/* #define WR7146(REGARDS,CTRLWORD) - writel(CTRLWORD,(uint32_t)(devpriv->base_addr+(REGARDS))) */ -#define WR7146(REGARDS, CTRLWORD) writel(CTRLWORD, devpriv->base_addr+(REGARDS)) + /* + * Send EEPROM target address: + * Byte2 = I2C command: write to I2C EEPROM device. + * Byte1 = EEPROM internal target address. + * Byte0 = Not sent. + */ + if (s626_i2c_handshake(dev, S626_I2C_B2(S626_I2C_ATTRSTART, + devpriv->i2c_adrs) | + S626_I2C_B1(S626_I2C_ATTRSTOP, addr) | + S626_I2C_B0(S626_I2C_ATTRNOP, 0))) + /* Abort function and declare error if handshake failed. */ + return 0; -/* #define RR7146(REGARDS) - readl((uint32_t)(devpriv->base_addr+(REGARDS))) */ -#define RR7146(REGARDS) readl(devpriv->base_addr+(REGARDS)) + /* + * Execute EEPROM read: + * Byte2 = I2C command: read from I2C EEPROM device. + * Byte1 receives uint8_t from EEPROM. + * Byte0 = Not sent. + */ + if (s626_i2c_handshake(dev, S626_I2C_B2(S626_I2C_ATTRSTART, + (devpriv->i2c_adrs | 1)) | + S626_I2C_B1(S626_I2C_ATTRSTOP, 0) | + S626_I2C_B0(S626_I2C_ATTRNOP, 0))) + /* Abort function and declare error if handshake failed. */ + return 0; -#define BUGFIX_STREG(REGADRS) (REGADRS - 4) + return (readl(devpriv->mmio + S626_P_I2CCTRL) >> 16) & 0xff; +} -/* Write a time slot control record to TSL2. */ -#define VECTPORT(VECTNUM) (P_TSL2 + ((VECTNUM) << 2)) -#define SETVECT(VECTNUM, VECTVAL) WR7146(VECTPORT(VECTNUM), (VECTVAL)) +/* *********** DAC FUNCTIONS *********** */ + +/* TrimDac LogicalChan-to-PhysicalChan mapping table. */ +static const uint8_t s626_trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 }; -/* Code macros used for constructing I2C command bytes. */ -#define I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) -#define I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) -#define I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) +/* TrimDac LogicalChan-to-EepromAdrs mapping table. */ +static const uint8_t s626_trimadrs[] = { + 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 +}; -static const struct comedi_lrange s626_range_table = { 2, { - RANGE(-5, 5), - RANGE(-10, 10), - } +enum { + s626_send_dac_wait_not_mc1_a2out, + s626_send_dac_wait_ssr_af2_out, + s626_send_dac_wait_fb_buffer2_msb_00, + s626_send_dac_wait_fb_buffer2_msb_ff }; -static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int s626_send_dac_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; + + switch (context) { + case s626_send_dac_wait_not_mc1_a2out: + status = readl(devpriv->mmio + S626_P_MC1); + if (!(status & S626_MC1_A2OUT)) + return 0; + break; + case s626_send_dac_wait_ssr_af2_out: + status = readl(devpriv->mmio + S626_P_SSR); + if (status & S626_SSR_AF2_OUT) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_00: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (!(status & 0xff000000)) + return 0; + break; + case s626_send_dac_wait_fb_buffer2_msb_ff: + status = readl(devpriv->mmio + S626_P_FB_BUFFER2); + if (status & 0xff000000) + return 0; + break; + default: + return -EINVAL; + } + return -EBUSY; +} + +/* + * Private helper function: Transmit serial data to DAC via Audio + * channel 2. Assumes: (1) TSL2 slot records initialized, and (2) + * dacpol contains valid target image. + */ +static int s626_send_dac(struct comedi_device *dev, uint32_t val) { -/* uint8_t PollList; */ -/* uint16_t AdcData; */ -/* uint16_t StartVal; */ -/* uint16_t index; */ -/* unsigned int data[16]; */ - int result; - int i; + struct s626_private *devpriv = dev->private; int ret; - resource_size_t resourceStart; - dma_addr_t appdma; - struct comedi_subdevice *s; - const struct pci_device_id *ids; - struct pci_dev *pdev = NULL; - if (alloc_private(dev, sizeof(struct s626_private)) < 0) - return -ENOMEM; + /* START THE SERIAL CLOCK RUNNING ------------- */ - for (i = 0; i < (ARRAY_SIZE(s626_pci_table) - 1) && !pdev; i++) { - ids = &s626_pci_table[i]; - do { - pdev = pci_get_subsys(ids->vendor, ids->device, - ids->subvendor, ids->subdevice, - pdev); - - if ((it->options[0] || it->options[1]) && pdev) { - /* matches requested bus/slot */ - if (pdev->bus->number == it->options[0] && - PCI_SLOT(pdev->devfn) == it->options[1]) - break; - } else - break; - } while (1); - } - devpriv->pdev = pdev; + /* + * Assert DAC polarity control and enable gating of DAC serial clock + * and audio bit stream signals. At this point in time we must be + * assured of being in time slot 0. If we are not in slot 0, the + * serial clock and audio stream signals will be disabled; this is + * because the following s626_debi_write statement (which enables + * signals to be passed through the gate array) would execute before + * the trailing edge of WS1/WS3 (which turns off the signals), thus + * causing the signals to be inactive during the DAC write. + */ + s626_debi_write(dev, S626_LP_DACPOL, devpriv->dacpol); + + /* TRANSFER OUTPUT DWORD VALUE INTO A2'S OUTPUT FIFO ---------------- */ + + /* Copy DAC setpoint value to DAC's output DMA buffer. */ + /* writel(val, devpriv->mmio + (uint32_t)devpriv->dac_wbuf); */ + *devpriv->dac_wbuf = val; + + /* + * Enable the output DMA transfer. This will cause the DMAC to copy + * the DAC's data value to A2's output FIFO. The DMA transfer will + * then immediately terminate because the protection address is + * reached upon transfer of the first DWORD value. + */ + s626_mc_enable(dev, S626_MC1_A2OUT, S626_P_MC1); + + /* While the DMA transfer is executing ... */ - if (pdev == NULL) { - printk(KERN_ERR "s626_attach: Board not present!!!\n"); - return -ENODEV; + /* + * Reset Audio2 output FIFO's underflow flag (along with any + * other FIFO underflow/overflow flags). When set, this flag + * will indicate that we have emerged from slot 0. + */ + writel(S626_ISR_AFOU, devpriv->mmio + S626_P_ISR); + + /* + * Wait for the DMA transfer to finish so that there will be data + * available in the FIFO when time slot 1 tries to transfer a DWORD + * from the FIFO to the output buffer register. We test for DMA + * Done by polling the DMAC enable flag; this flag is automatically + * cleared when the transfer has finished. + */ + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_not_mc1_a2out); + if (ret) { + comedi_error(dev, "DMA transfer timeout."); + return ret; } - result = comedi_pci_enable(pdev, "s626"); - if (result < 0) { - printk(KERN_ERR "s626_attach: comedi_pci_enable fails\n"); - return -ENODEV; + /* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */ + + /* + * FIFO data is now available, so we enable execution of time slots + * 1 and higher by clearing the EOS flag in slot 0. Note that SD3 + * will be shifted in and stored in FB_BUFFER2 for end-of-slot-list + * detection. + */ + writel(S626_XSD2 | S626_RSD3 | S626_SIB_A2, + devpriv->mmio + S626_VECTPORT(0)); + + /* + * Wait for slot 1 to execute to ensure that the Packet will be + * transmitted. This is detected by polling the Audio2 output FIFO + * underflow flag, which will be set when slot 1 execution has + * finished transferring the DAC's data DWORD from the output FIFO + * to the output buffer register. + */ + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_ssr_af2_out); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 1 to execute."); + return ret; } - devpriv->got_regions = 1; - resourceStart = pci_resource_start(devpriv->pdev, 0); + /* + * Set up to trap execution at slot 0 when the TSL sequencer cycles + * back to slot 0 after executing the EOS in slot 5. Also, + * simultaneously shift out and in the 0x00 that is ALWAYS the value + * stored in the last byte to be shifted out of the FIFO's DWORD + * buffer register. + */ + writel(S626_XSD2 | S626_XFIFO_2 | S626_RSD2 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); - devpriv->base_addr = ioremap(resourceStart, SIZEOF_ADDRESS_SPACE); - if (devpriv->base_addr == NULL) { - printk(KERN_ERR "s626_attach: IOREMAP failed\n"); - return -ENODEV; + /* WAIT FOR THE TRANSACTION TO FINISH ----------------------- */ + + /* + * Wait for the TSL to finish executing all time slots before + * exiting this function. We must do this so that the next DAC + * write doesn't start, thereby enabling clock/chip select signals: + * + * 1. Before the TSL sequence cycles back to slot 0, which disables + * the clock/cs signal gating and traps slot // list execution. + * we have not yet finished slot 5 then the clock/cs signals are + * still gated and we have not finished transmitting the stream. + * + * 2. While slots 2-5 are executing due to a late slot 0 trap. In + * this case, the slot sequence is currently repeating, but with + * clock/cs signals disabled. We must wait for slot 0 to trap + * execution before setting up the next DAC setpoint DMA transfer + * and enabling the clock/cs signals. To detect the end of slot 5, + * we test for the FB_BUFFER2 MSB contents to be equal to 0xFF. If + * the TSL has not yet finished executing slot 5 ... + */ + if (readl(devpriv->mmio + S626_P_FB_BUFFER2) & 0xff000000) { + /* + * The trap was set on time and we are still executing somewhere + * in slots 2-5, so we now wait for slot 0 to execute and trap + * TSL execution. This is detected when FB_BUFFER2 MSB changes + * from 0xFF to 0x00, which slot 0 causes to happen by shifting + * out/in on SD2 the 0x00 that is always referenced by slot 5. + */ + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_00); + if (ret) { + comedi_error(dev, + "TSL timeout waiting for slot 0 to execute."); + return ret; + } } + /* + * Either (1) we were too late setting the slot 0 trap; the TSL + * sequencer restarted slot 0 before we could set the EOS trap flag, + * or (2) we were not late and execution is now trapped at slot 0. + * In either case, we must now change slot 0 so that it will store + * value 0xFF (instead of 0x00) to FB_BUFFER2 next time it executes. + * In order to do this, we reprogram slot 0 so that it will shift in + * SD3, which is driven only by a pull-up resistor. + */ + writel(S626_RSD3 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); - if (devpriv->base_addr) { - /* disable master interrupt */ - writel(0, devpriv->base_addr + P_IER); + /* + * Wait for slot 0 to execute, at which time the TSL is setup for + * the next DAC write. This is detected when FB_BUFFER2 MSB changes + * from 0x00 to 0xFF. + */ + ret = comedi_timeout(dev, NULL, NULL, s626_send_dac_eoc, + s626_send_dac_wait_fb_buffer2_msb_ff); + if (ret) { + comedi_error(dev, "TSL timeout waiting for slot 0 to execute."); + return ret; + } + return 0; +} - /* soft reset */ - writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1); +/* + * Private helper function: Write setpoint to an application DAC channel. + */ +static int s626_set_dac(struct comedi_device *dev, uint16_t chan, + int16_t dacdata) +{ + struct s626_private *devpriv = dev->private; + uint16_t signmask; + uint32_t ws_image; + uint32_t val; - /* DMA FIXME DMA// */ - DEBUG("s626_attach: DMA ALLOCATION\n"); + /* + * Adjust DAC data polarity and set up Polarity Control Register image. + */ + signmask = 1 << chan; + if (dacdata < 0) { + dacdata = -dacdata; + devpriv->dacpol |= signmask; + } else { + devpriv->dacpol &= ~signmask; + } - /* adc buffer allocation */ - devpriv->allocatedBuf = 0; + /* Limit DAC setpoint value to valid range. */ + if ((uint16_t)dacdata > 0x1FFF) + dacdata = 0x1FFF; - devpriv->ANABuf.LogicalBase = - pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma); + /* + * Set up TSL2 records (aka "vectors") for DAC update. Vectors V2 + * and V3 transmit the setpoint to the target DAC. V4 and V5 send + * data to a non-existent TrimDac channel just to keep the clock + * running after sending data to the target DAC. This is necessary + * to eliminate the clock glitch that would otherwise occur at the + * end of the target DAC's serial data stream. When the sequence + * restarts at V0 (after executing V5), the gate array automatically + * disables gating for the DAC clock and all DAC chip selects. + */ - if (devpriv->ANABuf.LogicalBase == NULL) { - printk(KERN_ERR "s626_attach: DMA Memory mapping error\n"); - return -ENOMEM; - } + /* Choose DAC chip select to be asserted */ + ws_image = (chan & 2) ? S626_WS1 : S626_WS2; + /* Slot 2: Transmit high data byte to target DAC */ + writel(S626_XSD2 | S626_XFIFO_1 | ws_image, + devpriv->mmio + S626_VECTPORT(2)); + /* Slot 3: Transmit low data byte to target DAC */ + writel(S626_XSD2 | S626_XFIFO_0 | ws_image, + devpriv->mmio + S626_VECTPORT(3)); + /* Slot 4: Transmit to non-existent TrimDac channel to keep clock */ + writel(S626_XSD2 | S626_XFIFO_3 | S626_WS3, + devpriv->mmio + S626_VECTPORT(4)); + /* Slot 5: running after writing target DAC's low data byte */ + writel(S626_XSD2 | S626_XFIFO_2 | S626_WS3 | S626_EOS, + devpriv->mmio + S626_VECTPORT(5)); + + /* + * Construct and transmit target DAC's serial packet: + * (A10D DDDD), (DDDD DDDD), (0x0F), (0x00) where A is chan<0>, + * and D<12:0> is the DAC setpoint. Append a WORD value (that writes + * to a non-existent TrimDac channel) that serves to keep the clock + * running after the packet has been sent to the target DAC. + */ + val = 0x0F000000; /* Continue clock after target DAC data + * (write to non-existent trimdac). */ + val |= 0x00004000; /* Address the two main dual-DAC devices + * (TSL's chip select enables target device). */ + val |= ((uint32_t)(chan & 1) << 15); /* Address the DAC channel + * within the device. */ + val |= (uint32_t)dacdata; /* Include DAC setpoint data. */ + return s626_send_dac(dev, val); +} - devpriv->ANABuf.PhysicalBase = appdma; +static int s626_write_trim_dac(struct comedi_device *dev, uint8_t logical_chan, + uint8_t dac_data) +{ + struct s626_private *devpriv = dev->private; + uint32_t chan; - DEBUG - ("s626_attach: AllocDMAB ADC Logical=%p, bsize=%d, Physical=0x%x\n", - devpriv->ANABuf.LogicalBase, DMABUF_SIZE, - (uint32_t) devpriv->ANABuf.PhysicalBase); + /* + * Save the new setpoint in case the application needs to read it back + * later. + */ + devpriv->trim_setpoint[logical_chan] = (uint8_t)dac_data; - devpriv->allocatedBuf++; + /* Map logical channel number to physical channel number. */ + chan = s626_trimchan[logical_chan]; - devpriv->RPSBuf.LogicalBase = - pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma); + /* + * Set up TSL2 records for TrimDac write operation. All slots shift + * 0xFF in from pulled-up SD3 so that the end of the slot sequence + * can be detected. + */ - if (devpriv->RPSBuf.LogicalBase == NULL) { - printk(KERN_ERR "s626_attach: DMA Memory mapping error\n"); - return -ENOMEM; - } + /* Slot 2: Send high uint8_t to target TrimDac */ + writel(S626_XSD2 | S626_XFIFO_1 | S626_WS3, + devpriv->mmio + S626_VECTPORT(2)); + /* Slot 3: Send low uint8_t to target TrimDac */ + writel(S626_XSD2 | S626_XFIFO_0 | S626_WS3, + devpriv->mmio + S626_VECTPORT(3)); + /* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running */ + writel(S626_XSD2 | S626_XFIFO_3 | S626_WS1, + devpriv->mmio + S626_VECTPORT(4)); + /* Slot 5: Send NOP low uint8_t to DAC0 */ + writel(S626_XSD2 | S626_XFIFO_2 | S626_WS1 | S626_EOS, + devpriv->mmio + S626_VECTPORT(5)); - devpriv->RPSBuf.PhysicalBase = appdma; + /* + * Construct and transmit target DAC's serial packet: + * (0000 AAAA), (DDDD DDDD), (0x00), (0x00) where A<3:0> is the + * DAC channel's address, and D<7:0> is the DAC setpoint. Append a + * WORD value (that writes a channel 0 NOP command to a non-existent + * main DAC channel) that serves to keep the clock running after the + * packet has been sent to the target DAC. + */ - DEBUG - ("s626_attach: AllocDMAB RPS Logical=%p, bsize=%d, Physical=0x%x\n", - devpriv->RPSBuf.LogicalBase, DMABUF_SIZE, - (uint32_t) devpriv->RPSBuf.PhysicalBase); + /* + * Address the DAC channel within the trimdac device. + * Include DAC setpoint data. + */ + return s626_send_dac(dev, (chan << 8) | dac_data); +} - devpriv->allocatedBuf++; +static int s626_load_trim_dacs(struct comedi_device *dev) +{ + uint8_t i; + int ret; + /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ + for (i = 0; i < ARRAY_SIZE(s626_trimchan); i++) { + ret = s626_write_trim_dac(dev, i, + s626_i2c_read(dev, s626_trimadrs[i])); + if (ret) + return ret; } + return 0; +} - dev->board_ptr = s626_boards; - dev->board_name = thisboard->name; +/* ****** COUNTER FUNCTIONS ******* */ - if (alloc_subdevices(dev, 6) < 0) - return -ENOMEM; +/* + * All counter functions address a specific counter by means of the + * "Counter" argument, which is a logical counter number. The Counter + * argument may have any of the following legal values: 0=0A, 1=1A, + * 2=2A, 3=0B, 4=1B, 5=2B. + */ - dev->iobase = (unsigned long)devpriv->base_addr; - dev->irq = devpriv->pdev->irq; +/* + * Read a counter's output latch. + */ +static uint32_t s626_read_latch(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint32_t value; - /* set up interrupt handler */ - if (dev->irq == 0) { - printk(KERN_ERR " unknown irq (bad)\n"); - } else { - ret = request_irq(dev->irq, s626_irq_handler, IRQF_SHARED, - "s626", dev); + /* Latch counts and fetch LSW of latched counts value. */ + value = s626_debi_read(dev, k->my_latch_lsw); - if (ret < 0) { - printk(KERN_ERR " irq not available\n"); - dev->irq = 0; - } + /* Fetch MSW of latched counts and combine with LSW. */ + value |= ((uint32_t)s626_debi_read(dev, k->my_latch_lsw + 2) << 16); + + /* Return latched counts. */ + return value; +} + +/* + * Return/set a counter pair's latch trigger source. 0: On read + * access, 1: A index latches A, 2: B index latches B, 3: A overflow + * latches B. + */ +static void s626_set_latch_source(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_LATCHSRC), + S626_SET_CRB_LATCHSRC(value)); +} + +/* + * Write value into counter preload register. + */ +static void s626_preload(struct comedi_device *dev, + const struct s626_enc_info *k, uint32_t value) +{ + s626_debi_write(dev, k->my_latch_lsw, value); + s626_debi_write(dev, k->my_latch_lsw + 2, value >> 16); +} + +/* ****** PRIVATE COUNTER FUNCTIONS ****** */ + +/* + * Reset a counter's index and overflow event capture flags. + */ +static void s626_reset_cap_flags_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + (S626_SET_CRB_INTRESETCMD(1) | + S626_SET_CRB_INTRESET_A(1))); +} + +static void s626_reset_cap_flags_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + (S626_SET_CRB_INTRESETCMD(1) | + S626_SET_CRB_INTRESET_B(1))); +} + +/* + * Return counter setup in a format (COUNTER_SETUP) that is consistent + * for both A and B counters. + */ +static uint16_t s626_get_mode_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; + uint16_t crb; + uint16_t setup; + unsigned cntsrc, clkmult, clkpol, encmode; + + /* Fetch CRA and CRB register images. */ + cra = s626_debi_read(dev, k->my_cra); + crb = s626_debi_read(dev, k->my_crb); + + /* + * Populate the standardized counter setup bit fields. + */ + setup = + /* LoadSrc = LoadSrcA. */ + S626_SET_STD_LOADSRC(S626_GET_CRA_LOADSRC_A(cra)) | + /* LatchSrc = LatchSrcA. */ + S626_SET_STD_LATCHSRC(S626_GET_CRB_LATCHSRC(crb)) | + /* IntSrc = IntSrcA. */ + S626_SET_STD_INTSRC(S626_GET_CRA_INTSRC_A(cra)) | + /* IndxSrc = IndxSrcA. */ + S626_SET_STD_INDXSRC(S626_GET_CRA_INDXSRC_A(cra)) | + /* IndxPol = IndxPolA. */ + S626_SET_STD_INDXPOL(S626_GET_CRA_INDXPOL_A(cra)) | + /* ClkEnab = ClkEnabA. */ + S626_SET_STD_CLKENAB(S626_GET_CRB_CLKENAB_A(crb)); + + /* Adjust mode-dependent parameters. */ + cntsrc = S626_GET_CRA_CNTSRC_A(cra); + if (cntsrc & S626_CNTSRC_SYSCLK) { + /* Timer mode (CntSrcA<1> == 1): */ + encmode = S626_ENCMODE_TIMER; + /* Set ClkPol to indicate count direction (CntSrcA<0>). */ + clkpol = cntsrc & 1; + /* ClkMult must be 1x in Timer mode. */ + clkmult = S626_CLKMULT_1X; + } else { + /* Counter mode (CntSrcA<1> == 0): */ + encmode = S626_ENCMODE_COUNTER; + /* Pass through ClkPol. */ + clkpol = S626_GET_CRA_CLKPOL_A(cra); + /* Force ClkMult to 1x if not legal, else pass through. */ + clkmult = S626_GET_CRA_CLKMULT_A(cra); + if (clkmult == S626_CLKMULT_SPECIAL) + clkmult = S626_CLKMULT_1X; } + setup |= S626_SET_STD_ENCMODE(encmode) | S626_SET_STD_CLKMULT(clkmult) | + S626_SET_STD_CLKPOL(clkpol); - DEBUG("s626_attach: -- it opts %d,%d --\n", - it->options[0], it->options[1]); + /* Return adjusted counter setup. */ + return setup; +} - s = dev->subdevices + 0; - /* analog input subdevice */ - dev->read_subdev = s; - /* we support single-ended (ground) and differential */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ; - s->n_chan = thisboard->ai_chans; - s->maxdata = (0xffff >> 2); - s->range_table = &s626_range_table; - s->len_chanlist = thisboard->ai_chans; /* This is the maximum chanlist - length that the board can - handle */ - s->insn_config = s626_ai_insn_config; - s->insn_read = s626_ai_insn_read; - s->do_cmd = s626_ai_cmd; - s->do_cmdtest = s626_ai_cmdtest; - s->cancel = s626_ai_cancel; - - s = dev->subdevices + 1; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = thisboard->ao_chans; - s->maxdata = (0x3fff); - s->range_table = &range_bipolar10; - s->insn_write = s626_ao_winsn; - s->insn_read = s626_ao_rinsn; - - s = dev->subdevices + 2; - /* digital I/O subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = S626_DIO_CHANNELS; - s->maxdata = 1; - s->io_bits = 0xffff; - s->private = &dio_private_A; - s->range_table = &range_digital; - s->insn_config = s626_dio_insn_config; - s->insn_bits = s626_dio_insn_bits; - - s = dev->subdevices + 3; - /* digital I/O subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->io_bits = 0xffff; - s->private = &dio_private_B; - s->range_table = &range_digital; - s->insn_config = s626_dio_insn_config; - s->insn_bits = s626_dio_insn_bits; - - s = dev->subdevices + 4; - /* digital I/O subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->io_bits = 0xffff; - s->private = &dio_private_C; - s->range_table = &range_digital; - s->insn_config = s626_dio_insn_config; - s->insn_bits = s626_dio_insn_bits; - - s = dev->subdevices + 5; - /* encoder (counter) subdevice */ - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL; - s->n_chan = thisboard->enc_chans; - s->private = enc_private_data; - s->insn_config = s626_enc_insn_config; - s->insn_read = s626_enc_insn_read; - s->insn_write = s626_enc_insn_write; - s->maxdata = 0xffffff; - s->range_table = &range_unknown; - - /* stop ai_command */ - devpriv->ai_cmd_running = 0; +static uint16_t s626_get_mode_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; + uint16_t crb; + uint16_t setup; + unsigned cntsrc, clkmult, clkpol, encmode; - if (devpriv->base_addr && (devpriv->allocatedBuf == 2)) { - dma_addr_t pPhysBuf; - uint16_t chan; - - /* enab DEBI and audio pins, enable I2C interface. */ - MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C); - /* Configure DEBI operating mode. */ - WR7146(P_DEBICFG, DEBI_CFG_SLAVE16 /* Local bus is 16 */ - /* bits wide. */ - | (DEBI_TOUT << DEBI_CFG_TOUT_BIT) - - /* Declare DEBI */ - /* transfer timeout */ - /* interval. */ - |DEBI_SWAP /* Set up byte lane */ - /* steering. */ - | DEBI_CFG_INTEL); /* Intel-compatible */ - /* local bus (DEBI */ - /* never times out). */ - DEBUG("s626_attach: %d debi init -- %d\n", - DEBI_CFG_SLAVE16 | (DEBI_TOUT << DEBI_CFG_TOUT_BIT) | - DEBI_SWAP | DEBI_CFG_INTEL, - DEBI_CFG_INTEL | DEBI_CFG_TOQ | DEBI_CFG_INCQ | - DEBI_CFG_16Q); - - /* DEBI INIT S626 WR7146( P_DEBICFG, DEBI_CFG_INTEL | DEBI_CFG_TOQ */ - /* | DEBI_CFG_INCQ| DEBI_CFG_16Q); //end */ - - /* Paging is disabled. */ - WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE); /* Disable MMU paging. */ - - /* Init GPIO so that ADC Start* is negated. */ - WR7146(P_GPIO, GPIO_BASE | GPIO1_HI); - - /* IsBoardRevA is a boolean that indicates whether the board is RevA. - * - * VERSION 2.01 CHANGE: REV A & B BOARDS NOW SUPPORTED BY DYNAMIC - * EEPROM ADDRESS SELECTION. Initialize the I2C interface, which - * is used to access the onboard serial EEPROM. The EEPROM's I2C - * DeviceAddress is hardwired to a value that is dependent on the - * 626 board revision. On all board revisions, the EEPROM stores - * TrimDAC calibration constants for analog I/O. On RevB and - * higher boards, the DeviceAddress is hardwired to 0 to enable - * the EEPROM to also store the PCI SubVendorID and SubDeviceID; - * this is the address at which the SAA7146 expects a - * configuration EEPROM to reside. On RevA boards, the EEPROM - * device address, which is hardwired to 4, prevents the SAA7146 - * from retrieving PCI sub-IDs, so the SAA7146 uses its built-in - * default values, instead. - */ + /* Fetch CRA and CRB register images. */ + cra = s626_debi_read(dev, k->my_cra); + crb = s626_debi_read(dev, k->my_crb); - /* devpriv->I2Cards= IsBoardRevA ? 0xA8 : 0xA0; // Set I2C EEPROM */ - /* DeviceType (0xA0) */ - /* and DeviceAddress<<1. */ - - devpriv->I2CAdrs = 0xA0; /* I2C device address for onboard */ - /* eeprom(revb) */ - - /* Issue an I2C ABORT command to halt any I2C operation in */ - /* progress and reset BUSY flag. */ - WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT); - /* Write I2C control: abort any I2C activity. */ - MC_ENABLE(P_MC2, MC2_UPLD_IIC); - /* Invoke command upload */ - while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0) - ; - /* and wait for upload to complete. */ - - /* Per SAA7146 data sheet, write to STATUS reg twice to - * reset all I2C error flags. */ - for (i = 0; i < 2; i++) { - WR7146(P_I2CSTAT, I2C_CLKSEL); - /* Write I2C control: reset error flags. */ - MC_ENABLE(P_MC2, MC2_UPLD_IIC); /* Invoke command upload */ - while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) - ; - /* and wait for upload to complete. */ - } + /* + * Populate the standardized counter setup bit fields. + */ + setup = + /* IntSrc = IntSrcB. */ + S626_SET_STD_INTSRC(S626_GET_CRB_INTSRC_B(crb)) | + /* LatchSrc = LatchSrcB. */ + S626_SET_STD_LATCHSRC(S626_GET_CRB_LATCHSRC(crb)) | + /* LoadSrc = LoadSrcB. */ + S626_SET_STD_LOADSRC(S626_GET_CRB_LOADSRC_B(crb)) | + /* IndxPol = IndxPolB. */ + S626_SET_STD_INDXPOL(S626_GET_CRB_INDXPOL_B(crb)) | + /* ClkEnab = ClkEnabB. */ + S626_SET_STD_CLKENAB(S626_GET_CRB_CLKENAB_B(crb)) | + /* IndxSrc = IndxSrcB. */ + S626_SET_STD_INDXSRC(S626_GET_CRA_INDXSRC_B(cra)); + + /* Adjust mode-dependent parameters. */ + cntsrc = S626_GET_CRA_CNTSRC_B(cra); + clkmult = S626_GET_CRB_CLKMULT_B(crb); + if (clkmult == S626_CLKMULT_SPECIAL) { + /* Extender mode (ClkMultB == S626_CLKMULT_SPECIAL): */ + encmode = S626_ENCMODE_EXTENDER; + /* Indicate multiplier is 1x. */ + clkmult = S626_CLKMULT_1X; + /* Set ClkPol equal to Timer count direction (CntSrcB<0>). */ + clkpol = cntsrc & 1; + } else if (cntsrc & S626_CNTSRC_SYSCLK) { + /* Timer mode (CntSrcB<1> == 1): */ + encmode = S626_ENCMODE_TIMER; + /* Indicate multiplier is 1x. */ + clkmult = S626_CLKMULT_1X; + /* Set ClkPol equal to Timer count direction (CntSrcB<0>). */ + clkpol = cntsrc & 1; + } else { + /* If Counter mode (CntSrcB<1> == 0): */ + encmode = S626_ENCMODE_COUNTER; + /* Clock multiplier is passed through. */ + /* Clock polarity is passed through. */ + clkpol = S626_GET_CRB_CLKPOL_B(crb); + } + setup |= S626_SET_STD_ENCMODE(encmode) | S626_SET_STD_CLKMULT(clkmult) | + S626_SET_STD_CLKPOL(clkpol); - /* Init audio interface functional attributes: set DAC/ADC - * serial clock rates, invert DAC serial clock so that - * DAC data setup times are satisfied, enable DAC serial - * clock out. - */ + /* Return adjusted counter setup. */ + return setup; +} - WR7146(P_ACON2, ACON2_INIT); +/* + * Set the operating mode for the specified counter. The setup + * parameter is treated as a COUNTER_SETUP data type. The following + * parameters are programmable (all other parms are ignored): ClkMult, + * ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc. + */ +static void s626_set_mode_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src) +{ + struct s626_private *devpriv = dev->private; + uint16_t cra; + uint16_t crb; + unsigned cntsrc, clkmult, clkpol; + + /* Initialize CRA and CRB images. */ + /* Preload trigger is passed through. */ + cra = S626_SET_CRA_LOADSRC_A(S626_GET_STD_LOADSRC(setup)); + /* IndexSrc is passed through. */ + cra |= S626_SET_CRA_INDXSRC_A(S626_GET_STD_INDXSRC(setup)); + + /* Reset any pending CounterA event captures. */ + crb = S626_SET_CRB_INTRESETCMD(1) | S626_SET_CRB_INTRESET_A(1); + /* Clock enable is passed through. */ + crb |= S626_SET_CRB_CLKENAB_A(S626_GET_STD_CLKENAB(setup)); + + /* Force IntSrc to Disabled if disable_int_src is asserted. */ + if (!disable_int_src) + cra |= S626_SET_CRA_INTSRC_A(S626_GET_STD_INTSRC(setup)); + + /* Populate all mode-dependent attributes of CRA & CRB images. */ + clkpol = S626_GET_STD_CLKPOL(setup); + switch (S626_GET_STD_ENCMODE(setup)) { + case S626_ENCMODE_EXTENDER: /* Extender Mode: */ + /* Force to Timer mode (Extender valid only for B counters). */ + /* Fall through to case S626_ENCMODE_TIMER: */ + case S626_ENCMODE_TIMER: /* Timer Mode: */ + /* CntSrcA<1> selects system clock */ + cntsrc = S626_CNTSRC_SYSCLK; + /* Count direction (CntSrcA<0>) obtained from ClkPol. */ + cntsrc |= clkpol; + /* ClkPolA behaves as always-on clock enable. */ + clkpol = 1; + /* ClkMult must be 1x. */ + clkmult = S626_CLKMULT_1X; + break; + default: /* Counter Mode: */ + /* Select ENC_C and ENC_D as clock/direction inputs. */ + cntsrc = S626_CNTSRC_ENCODER; + /* Clock polarity is passed through. */ + /* Force multiplier to x1 if not legal, else pass through. */ + clkmult = S626_GET_STD_CLKMULT(setup); + if (clkmult == S626_CLKMULT_SPECIAL) + clkmult = S626_CLKMULT_1X; + break; + } + cra |= S626_SET_CRA_CNTSRC_A(cntsrc) | S626_SET_CRA_CLKPOL_A(clkpol) | + S626_SET_CRA_CLKMULT_A(clkmult); - /* Set up TSL1 slot list, which is used to control the - * accumulation of ADC data: RSD1 = shift data in on SD1. - * SIB_A1 = store data uint8_t at next available location in - * FB BUFFER1 register. */ - WR7146(P_TSL1, RSD1 | SIB_A1); - /* Fetch ADC high data uint8_t. */ - WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS); - /* Fetch ADC low data uint8_t; end of TSL1. */ + /* + * Force positive index polarity if IndxSrc is software-driven only, + * otherwise pass it through. + */ + if (S626_GET_STD_INDXSRC(setup) != S626_INDXSRC_SOFT) + cra |= S626_SET_CRA_INDXPOL_A(S626_GET_STD_INDXPOL(setup)); - /* enab TSL1 slot list so that it executes all the time. */ - WR7146(P_ACON1, ACON1_ADCSTART); + /* + * If IntSrc has been forced to Disabled, update the MISC2 interrupt + * enable mask to indicate the counter interrupt is disabled. + */ + if (disable_int_src) + devpriv->counter_int_enabs &= ~k->my_event_bits[3]; - /* Initialize RPS registers used for ADC. */ + /* + * While retaining CounterB and LatchSrc configurations, program the + * new counter operating mode. + */ + s626_debi_replace(dev, k->my_cra, + S626_CRAMSK_INDXSRC_B | S626_CRAMSK_CNTSRC_B, cra); + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_A), crb); +} - /* Physical start of RPS program. */ - WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase); +static void s626_set_mode_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t setup, + uint16_t disable_int_src) +{ + struct s626_private *devpriv = dev->private; + uint16_t cra; + uint16_t crb; + unsigned cntsrc, clkmult, clkpol; + + /* Initialize CRA and CRB images. */ + /* IndexSrc is passed through. */ + cra = S626_SET_CRA_INDXSRC_B(S626_GET_STD_INDXSRC(setup)); + + /* Reset event captures and disable interrupts. */ + crb = S626_SET_CRB_INTRESETCMD(1) | S626_SET_CRB_INTRESET_B(1); + /* Clock enable is passed through. */ + crb |= S626_SET_CRB_CLKENAB_B(S626_GET_STD_CLKENAB(setup)); + /* Preload trigger source is passed through. */ + crb |= S626_SET_CRB_LOADSRC_B(S626_GET_STD_LOADSRC(setup)); + + /* Force IntSrc to Disabled if disable_int_src is asserted. */ + if (!disable_int_src) + crb |= S626_SET_CRB_INTSRC_B(S626_GET_STD_INTSRC(setup)); + + /* Populate all mode-dependent attributes of CRA & CRB images. */ + clkpol = S626_GET_STD_CLKPOL(setup); + switch (S626_GET_STD_ENCMODE(setup)) { + case S626_ENCMODE_TIMER: /* Timer Mode: */ + /* CntSrcB<1> selects system clock */ + cntsrc = S626_CNTSRC_SYSCLK; + /* with direction (CntSrcB<0>) obtained from ClkPol. */ + cntsrc |= clkpol; + /* ClkPolB behaves as always-on clock enable. */ + clkpol = 1; + /* ClkMultB must be 1x. */ + clkmult = S626_CLKMULT_1X; + break; + case S626_ENCMODE_EXTENDER: /* Extender Mode: */ + /* CntSrcB source is OverflowA (same as "timer") */ + cntsrc = S626_CNTSRC_SYSCLK; + /* with direction obtained from ClkPol. */ + cntsrc |= clkpol; + /* ClkPolB controls IndexB -- always set to active. */ + clkpol = 1; + /* ClkMultB selects OverflowA as the clock source. */ + clkmult = S626_CLKMULT_SPECIAL; + break; + default: /* Counter Mode: */ + /* Select ENC_C and ENC_D as clock/direction inputs. */ + cntsrc = S626_CNTSRC_ENCODER; + /* ClkPol is passed through. */ + /* Force ClkMult to x1 if not legal, otherwise pass through. */ + clkmult = S626_GET_STD_CLKMULT(setup); + if (clkmult == S626_CLKMULT_SPECIAL) + clkmult = S626_CLKMULT_1X; + break; + } + cra |= S626_SET_CRA_CNTSRC_B(cntsrc); + crb |= S626_SET_CRB_CLKPOL_B(clkpol) | S626_SET_CRB_CLKMULT_B(clkmult); - WR7146(P_RPSPAGE1, 0); - /* RPS program performs no explicit mem writes. */ - WR7146(P_RPS1_TOUT, 0); /* Disable RPS timeouts. */ + /* + * Force positive index polarity if IndxSrc is software-driven only, + * otherwise pass it through. + */ + if (S626_GET_STD_INDXSRC(setup) != S626_INDXSRC_SOFT) + crb |= S626_SET_CRB_INDXPOL_B(S626_GET_STD_INDXPOL(setup)); - /* SAA7146 BUG WORKAROUND. Initialize SAA7146 ADC interface - * to a known state by invoking ADCs until FB BUFFER 1 - * register shows that it is correctly receiving ADC data. - * This is necessary because the SAA7146 ADC interface does - * not start up in a defined state after a PCI reset. - */ + /* + * If IntSrc has been forced to Disabled, update the MISC2 interrupt + * enable mask to indicate the counter interrupt is disabled. + */ + if (disable_int_src) + devpriv->counter_int_enabs &= ~k->my_event_bits[3]; -/* PollList = EOPL; // Create a simple polling */ -/* // list for analog input */ -/* // channel 0. */ -/* ResetADC( dev, &PollList ); */ + /* + * While retaining CounterA and LatchSrc configurations, program the + * new counter operating mode. + */ + s626_debi_replace(dev, k->my_cra, + ~(S626_CRAMSK_INDXSRC_B | S626_CRAMSK_CNTSRC_B), cra); + s626_debi_replace(dev, k->my_crb, + S626_CRBMSK_CLKENAB_A | S626_CRBMSK_LATCHSRC, crb); +} -/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */ -/* //Get initial ADC */ -/* //value. */ +/* + * Return/set a counter's enable. enab: 0=always enabled, 1=enabled by index. + */ +static void s626_set_enable_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_A), + S626_SET_CRB_CLKENAB_A(enab)); +} -/* StartVal = data[0]; */ +static void s626_set_enable_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t enab) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_INTCTRL | S626_CRBMSK_CLKENAB_B), + S626_SET_CRB_CLKENAB_B(enab)); +} -/* // VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. */ -/* // Invoke ADCs until the new ADC value differs from the initial */ -/* // value or a timeout occurs. The timeout protects against the */ -/* // possibility that the driver is restarting and the ADC data is a */ -/* // fixed value resulting from the applied ADC analog input being */ -/* // unusually quiet or at the rail. */ +static uint16_t s626_get_enable_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_CLKENAB_A(s626_debi_read(dev, k->my_crb)); +} -/* for ( index = 0; index < 500; index++ ) */ -/* { */ -/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); */ -/* AdcData = data[0]; //ReadADC( &AdcData ); */ -/* if ( AdcData != StartVal ) */ -/* break; */ -/* } */ +static uint16_t s626_get_enable_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_CLKENAB_B(s626_debi_read(dev, k->my_crb)); +} - /* end initADC */ +#ifdef unused +static uint16_t s626_get_latch_source(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_LATCHSRC(s626_debi_read(dev, k->my_crb)); +} +#endif - /* init the DAC interface */ +/* + * Return/set the event that will trigger transfer of the preload + * register into the counter. 0=ThisCntr_Index, 1=ThisCntr_Overflow, + * 2=OverflowA (B counters only), 3=disabled. + */ +static void s626_set_load_trig_a(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig) +{ + s626_debi_replace(dev, k->my_cra, ~S626_CRAMSK_LOADSRC_A, + S626_SET_CRA_LOADSRC_A(trig)); +} - /* Init Audio2's output DMAC attributes: burst length = 1 - * DWORD, threshold = 1 DWORD. - */ - WR7146(P_PCI_BT_A, 0); - - /* Init Audio2's output DMA physical addresses. The protection - * address is set to 1 DWORD past the base address so that a - * single DWORD will be transferred each time a DMA transfer is - * enabled. */ - - pPhysBuf = - devpriv->ANABuf.PhysicalBase + - (DAC_WDMABUF_OS * sizeof(uint32_t)); - - WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf); /* Buffer base adrs. */ - WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t))); /* Protection address. */ - - /* Cache Audio2's output DMA buffer logical address. This is - * where DAC data is buffered for A2 output DMA transfers. */ - devpriv->pDacWBuf = - (uint32_t *) devpriv->ANABuf.LogicalBase + DAC_WDMABUF_OS; - - /* Audio2's output channels does not use paging. The protection - * violation handling bit is set so that the DMAC will - * automatically halt and its PCI address pointer will be reset - * when the protection address is reached. */ - - WR7146(P_PAGEA2_OUT, 8); - - /* Initialize time slot list 2 (TSL2), which is used to control - * the clock generation for and serialization of data to be sent - * to the DAC devices. Slot 0 is a NOP that is used to trap TSL - * execution; this permits other slots to be safely modified - * without first turning off the TSL sequencer (which is - * apparently impossible to do). Also, SD3 (which is driven by a - * pull-up resistor) is shifted in and stored to the MSB of - * FB_BUFFER2 to be used as evidence that the slot sequence has - * not yet finished executing. - */ +static void s626_set_load_trig_b(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t trig) +{ + s626_debi_replace(dev, k->my_crb, + ~(S626_CRBMSK_LOADSRC_B | S626_CRBMSK_INTCTRL), + S626_SET_CRB_LOADSRC_B(trig)); +} - SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS); - /* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2. */ +static uint16_t s626_get_load_trig_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRA_LOADSRC_A(s626_debi_read(dev, k->my_cra)); +} - /* Initialize slot 1, which is constant. Slot 1 causes a - * DWORD to be transferred from audio channel 2's output FIFO - * to the FIFO's output buffer so that it can be serialized - * and sent to the DAC during subsequent slots. All remaining - * slots are dynamically populated as required by the target - * DAC device. - */ - SETVECT(1, LF_A2); - /* Slot 1: Fetch DWORD from Audio2's output FIFO. */ +static uint16_t s626_get_load_trig_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_LOADSRC_B(s626_debi_read(dev, k->my_crb)); +} - /* Start DAC's audio interface (TSL2) running. */ - WR7146(P_ACON1, ACON1_DACSTART); +/* + * Return/set counter interrupt source and clear any captured + * index/overflow events. int_source: 0=Disabled, 1=OverflowOnly, + * 2=IndexOnly, 3=IndexAndOverflow. + */ +static void s626_set_int_src_a(struct comedi_device *dev, + const struct s626_enc_info *k, + uint16_t int_source) +{ + struct s626_private *devpriv = dev->private; - /* end init DAC interface */ + /* Reset any pending counter overflow or index captures. */ + s626_debi_replace(dev, k->my_crb, ~S626_CRBMSK_INTCTRL, + (S626_SET_CRB_INTRESETCMD(1) | + S626_SET_CRB_INTRESET_A(1))); - /* Init Trim DACs to calibrated values. Do it twice because the - * SAA7146 audio channel does not always reset properly and - * sometimes causes the first few TrimDAC writes to malfunction. - */ + /* Program counter interrupt source. */ + s626_debi_replace(dev, k->my_cra, ~S626_CRAMSK_INTSRC_A, + S626_SET_CRA_INTSRC_A(int_source)); - LoadTrimDACs(dev); - LoadTrimDACs(dev); /* Insurance. */ + /* Update MISC2 interrupt enable mask. */ + devpriv->counter_int_enabs = + (devpriv->counter_int_enabs & ~k->my_event_bits[3]) | + k->my_event_bits[int_source]; +} - /* Manually init all gate array hardware in case this is a soft - * reset (we have no way of determining whether this is a warm - * or cold start). This is necessary because the gate array will - * reset only in response to a PCI hard reset; there is no soft - * reset function. */ +static void s626_set_int_src_b(struct comedi_device *dev, + const struct s626_enc_info *k, + uint16_t int_source) +{ + struct s626_private *devpriv = dev->private; + uint16_t crb; - /* Init all DAC outputs to 0V and init all DAC setpoint and - * polarity images. - */ - for (chan = 0; chan < S626_DAC_CHANNELS; chan++) - SetDAC(dev, chan, 0); + /* Cache writeable CRB register image. */ + crb = s626_debi_read(dev, k->my_crb) & ~S626_CRBMSK_INTCTRL; - /* Init image of WRMISC2 Battery Charger Enabled control bit. - * This image is used when the state of the charger control bit, - * which has no direct hardware readback mechanism, is queried. - */ - devpriv->ChargeEnabled = 0; + /* Reset any pending counter overflow or index captures. */ + s626_debi_write(dev, k->my_crb, (crb | S626_SET_CRB_INTRESETCMD(1) | + S626_SET_CRB_INTRESET_B(1))); - /* Init image of watchdog timer interval in WRMISC2. This image - * maintains the value of the control bits of MISC2 are - * continuously reset to zero as long as the WD timer is disabled. - */ - devpriv->WDInterval = 0; + /* Program counter interrupt source. */ + s626_debi_write(dev, k->my_crb, ((crb & ~S626_CRBMSK_INTSRC_B) | + S626_SET_CRB_INTSRC_B(int_source))); - /* Init Counter Interrupt enab mask for RDMISC2. This mask is - * applied against MISC2 when testing to determine which timer - * events are requesting interrupt service. - */ - devpriv->CounterIntEnabs = 0; + /* Update MISC2 interrupt enable mask. */ + devpriv->counter_int_enabs = + (devpriv->counter_int_enabs & ~k->my_event_bits[3]) | + k->my_event_bits[int_source]; +} - /* Init counters. */ - CountersInit(dev); +static uint16_t s626_get_int_src_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRA_INTSRC_A(s626_debi_read(dev, k->my_cra)); +} - /* Without modifying the state of the Battery Backup enab, disable - * the watchdog timer, set DIO channels 0-5 to operate in the - * standard DIO (vs. counter overflow) mode, disable the battery - * charger, and reset the watchdog interval selector to zero. - */ - WriteMISC2(dev, (uint16_t) (DEBIread(dev, - LP_RDMISC2) & - MISC2_BATT_ENABLE)); +static uint16_t s626_get_int_src_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_CRB_INTSRC_B(s626_debi_read(dev, k->my_crb)); +} - /* Initialize the digital I/O subsystem. */ - s626_dio_init(dev); +#ifdef unused +/* + * Return/set the clock multiplier. + */ +static void s626_set_clk_mult(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_CLKMULT) | + S626_SET_STD_CLKMULT(value)), false); +} - /* enable interrupt test */ - /* writel(IRQ_GPIO3 | IRQ_RPS1,devpriv->base_addr+P_IER); */ - } +static uint16_t s626_get_clk_mult(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_CLKMULT(k->get_mode(dev, k)); +} - DEBUG("s626_attach: comedi%d s626 attached %04x\n", dev->minor, - (uint32_t) devpriv->base_addr); +/* + * Return/set the clock polarity. + */ +static void s626_set_clk_pol(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_CLKPOL) | + S626_SET_STD_CLKPOL(value)), false); +} - return 1; +static uint16_t s626_get_clk_pol(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_CLKPOL(k->get_mode(dev, k)); } -static unsigned int s626_ai_reg_to_uint(int data) +/* + * Return/set the encoder mode. + */ +static void s626_set_enc_mode(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) { - unsigned int tempdata; + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_ENCMODE) | + S626_SET_STD_ENCMODE(value)), false); +} - tempdata = (data >> 18); - if (tempdata & 0x2000) - tempdata &= 0x1fff; - else - tempdata += (1 << 13); +static uint16_t s626_get_enc_mode(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_ENCMODE(k->get_mode(dev, k)); +} - return tempdata; +/* + * Return/set the index polarity. + */ +static void s626_set_index_pol(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) +{ + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_INDXPOL) | + S626_SET_STD_INDXPOL(value != 0)), false); } -/* static unsigned int s626_uint_to_reg(struct comedi_subdevice *s, int data){ */ -/* return 0; */ -/* } */ +static uint16_t s626_get_index_pol(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_INDXPOL(k->get_mode(dev, k)); +} -static irqreturn_t s626_irq_handler(int irq, void *d) +/* + * Return/set the index source. + */ +static void s626_set_index_src(struct comedi_device *dev, + const struct s626_enc_info *k, uint16_t value) { - struct comedi_device *dev = d; - struct comedi_subdevice *s; - struct comedi_cmd *cmd; - struct enc_private *k; - unsigned long flags; - int32_t *readaddr; - uint32_t irqtype, irqstatus; - int i = 0; - short tempdata; - uint8_t group; - uint16_t irqbit; + k->set_mode(dev, k, ((k->get_mode(dev, k) & ~S626_STDMSK_INDXSRC) | + S626_SET_STD_INDXSRC(value != 0)), false); +} - DEBUG("s626_irq_handler: interrupt request received!!!\n"); +static uint16_t s626_get_index_src(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + return S626_GET_STD_INDXSRC(k->get_mode(dev, k)); +} +#endif - if (dev->attached == 0) - return IRQ_NONE; - /* lock to avoid race with comedi_poll */ - spin_lock_irqsave(&dev->spinlock, flags); +/* + * Generate an index pulse. + */ +static void s626_pulse_index_a(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t cra; - /* save interrupt enable register state */ - irqstatus = readl(devpriv->base_addr + P_IER); + cra = s626_debi_read(dev, k->my_cra); + /* Pulse index. */ + s626_debi_write(dev, k->my_cra, (cra ^ S626_CRAMSK_INDXPOL_A)); + s626_debi_write(dev, k->my_cra, cra); +} - /* read interrupt type */ - irqtype = readl(devpriv->base_addr + P_ISR); +static void s626_pulse_index_b(struct comedi_device *dev, + const struct s626_enc_info *k) +{ + uint16_t crb; - /* disable master interrupt */ - writel(0, devpriv->base_addr + P_IER); + crb = s626_debi_read(dev, k->my_crb) & ~S626_CRBMSK_INTCTRL; + /* Pulse index. */ + s626_debi_write(dev, k->my_crb, (crb ^ S626_CRBMSK_INDXPOL_B)); + s626_debi_write(dev, k->my_crb, crb); +} - /* clear interrupt */ - writel(irqtype, devpriv->base_addr + P_ISR); +static const struct s626_enc_info s626_enc_chan_info[] = { + { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR0A, + .my_crb = S626_LP_CR0B, + .my_latch_lsw = S626_LP_CNTR0ALSW, + .my_event_bits = S626_EVBITS(0), + }, { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR1A, + .my_crb = S626_LP_CR1B, + .my_latch_lsw = S626_LP_CNTR1ALSW, + .my_event_bits = S626_EVBITS(1), + }, { + .get_enable = s626_get_enable_a, + .get_int_src = s626_get_int_src_a, + .get_load_trig = s626_get_load_trig_a, + .get_mode = s626_get_mode_a, + .pulse_index = s626_pulse_index_a, + .set_enable = s626_set_enable_a, + .set_int_src = s626_set_int_src_a, + .set_load_trig = s626_set_load_trig_a, + .set_mode = s626_set_mode_a, + .reset_cap_flags = s626_reset_cap_flags_a, + .my_cra = S626_LP_CR2A, + .my_crb = S626_LP_CR2B, + .my_latch_lsw = S626_LP_CNTR2ALSW, + .my_event_bits = S626_EVBITS(2), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR0A, + .my_crb = S626_LP_CR0B, + .my_latch_lsw = S626_LP_CNTR0BLSW, + .my_event_bits = S626_EVBITS(3), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR1A, + .my_crb = S626_LP_CR1B, + .my_latch_lsw = S626_LP_CNTR1BLSW, + .my_event_bits = S626_EVBITS(4), + }, { + .get_enable = s626_get_enable_b, + .get_int_src = s626_get_int_src_b, + .get_load_trig = s626_get_load_trig_b, + .get_mode = s626_get_mode_b, + .pulse_index = s626_pulse_index_b, + .set_enable = s626_set_enable_b, + .set_int_src = s626_set_int_src_b, + .set_load_trig = s626_set_load_trig_b, + .set_mode = s626_set_mode_b, + .reset_cap_flags = s626_reset_cap_flags_b, + .my_cra = S626_LP_CR2A, + .my_crb = S626_LP_CR2B, + .my_latch_lsw = S626_LP_CNTR2BLSW, + .my_event_bits = S626_EVBITS(5), + }, +}; - /* do somethings */ - DEBUG("s626_irq_handler: interrupt type %d\n", irqtype); +static unsigned int s626_ai_reg_to_uint(unsigned int data) +{ + return ((data >> 18) & 0x3fff) ^ 0x2000; +} - switch (irqtype) { - case IRQ_RPS1: /* end_of_scan occurs */ +static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan) +{ + unsigned int group = chan / 16; + unsigned int mask = 1 << (chan - (16 * group)); + unsigned int status; - DEBUG("s626_irq_handler: RPS1 irq detected\n"); + /* set channel to capture positive edge */ + status = s626_debi_read(dev, S626_LP_RDEDGSEL(group)); + s626_debi_write(dev, S626_LP_WREDGSEL(group), mask | status); - /* manage ai subdevice */ - s = dev->subdevices; - cmd = &(s->async->cmd); + /* enable interrupt on selected channel */ + status = s626_debi_read(dev, S626_LP_RDINTSEL(group)); + s626_debi_write(dev, S626_LP_WRINTSEL(group), mask | status); - /* Init ptr to DMA buffer that holds new ADC data. We skip the - * first uint16_t in the buffer because it contains junk data from - * the final ADC of the previous poll list scan. - */ - readaddr = (int32_t *) devpriv->ANABuf.LogicalBase + 1; - - /* get the data and hand it over to comedi */ - for (i = 0; i < (s->async->cmd.chanlist_len); i++) { - /* Convert ADC data to 16-bit integer values and copy to application */ - /* buffer. */ - tempdata = s626_ai_reg_to_uint((int)*readaddr); - readaddr++; - - /* put data into read buffer */ - /* comedi_buf_put(s->async, tempdata); */ - if (cfc_write_to_buffer(s, tempdata) == 0) - printk - ("s626_irq_handler: cfc_write_to_buffer error!\n"); - - DEBUG("s626_irq_handler: ai channel %d acquired: %d\n", - i, tempdata); - } + /* enable edge capture write command */ + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_EDCAP); - /* end of scan occurs */ - s->async->events |= COMEDI_CB_EOS; + /* enable edge capture on selected channel */ + status = s626_debi_read(dev, S626_LP_RDCAPSEL(group)); + s626_debi_write(dev, S626_LP_WRCAPSEL(group), mask | status); - if (!(devpriv->ai_continous)) - devpriv->ai_sample_count--; - if (devpriv->ai_sample_count <= 0) { - devpriv->ai_cmd_running = 0; + return 0; +} - /* Stop RPS program. */ - MC_DISABLE(P_MC1, MC1_ERPS1); +static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int group, + unsigned int mask) +{ + /* disable edge capture write command */ + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); - /* send end of acquisition */ - s->async->events |= COMEDI_CB_EOA; + /* enable edge capture on selected channel */ + s626_debi_write(dev, S626_LP_WRCAPSEL(group), mask); - /* disable master interrupt */ - irqstatus = 0; - } + return 0; +} - if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT) { - DEBUG - ("s626_irq_handler: enable interrupt on dio channel %d\n", - cmd->scan_begin_arg); +static int s626_dio_clear_irq(struct comedi_device *dev) +{ + unsigned int group; - s626_dio_set_irq(dev, cmd->scan_begin_arg); + /* disable edge capture write command */ + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); + + /* clear all dio pending events and interrupt */ + for (group = 0; group < S626_DIO_BANKS; group++) + s626_debi_write(dev, S626_LP_WRCAPSEL(group), 0xffff); + + return 0; +} + +static void s626_handle_dio_interrupt(struct comedi_device *dev, + uint16_t irqbit, uint8_t group) +{ + struct s626_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + + s626_dio_reset_irq(dev, group, irqbit); - DEBUG("s626_irq_handler: External trigger is set!!!\n"); + if (devpriv->ai_cmd_running) { + /* check if interrupt is an ai acquisition start trigger */ + if ((irqbit >> (cmd->start_arg - (16 * group))) == 1 && + cmd->start_src == TRIG_EXT) { + /* Start executing the RPS program */ + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); + + if (cmd->scan_begin_src == TRIG_EXT) + s626_dio_set_irq(dev, cmd->scan_begin_arg); } - /* tell comedi that data is there */ - DEBUG("s626_irq_handler: events %d\n", s->async->events); - comedi_event(dev, s); - break; - case IRQ_GPIO3: /* check dio and conter interrupt */ + if ((irqbit >> (cmd->scan_begin_arg - (16 * group))) == 1 && + cmd->scan_begin_src == TRIG_EXT) { + /* Trigger ADC scan loop start */ + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); - DEBUG("s626_irq_handler: GPIO3 irq detected\n"); + if (cmd->convert_src == TRIG_EXT) { + devpriv->ai_convert_count = cmd->chanlist_len; - /* manage ai subdevice */ - s = dev->subdevices; - cmd = &(s->async->cmd); + s626_dio_set_irq(dev, cmd->convert_arg); + } - /* s626_dio_clear_irq(dev); */ + if (cmd->convert_src == TRIG_TIMER) { + const struct s626_enc_info *k = + &s626_enc_chan_info[5]; - for (group = 0; group < S626_DIO_BANKS; group++) { - irqbit = 0; - /* read interrupt type */ - irqbit = DEBIread(dev, - ((struct dio_private *)(dev-> - subdevices + - 2 + - group)-> - private)->RDCapFlg); - - /* check if interrupt is generated from dio channels */ - if (irqbit) { - s626_dio_reset_irq(dev, group, irqbit); - DEBUG - ("s626_irq_handler: check interrupt on dio group %d %d\n", - group, i); - if (devpriv->ai_cmd_running) { - /* check if interrupt is an ai acquisition start trigger */ - if ((irqbit >> (cmd->start_arg - - (16 * group))) - == 1 && cmd->start_src == TRIG_EXT) { - DEBUG - ("s626_irq_handler: Edge capture interrupt received from channel %d\n", - cmd->start_arg); - - /* Start executing the RPS program. */ - MC_ENABLE(P_MC1, MC1_ERPS1); - - DEBUG - ("s626_irq_handler: acquisition start triggered!!!\n"); - - if (cmd->scan_begin_src == - TRIG_EXT) { - DEBUG - ("s626_ai_cmd: enable interrupt on dio channel %d\n", - cmd-> - scan_begin_arg); - - s626_dio_set_irq(dev, - cmd->scan_begin_arg); - - DEBUG - ("s626_irq_handler: External scan trigger is set!!!\n"); - } - } - if ((irqbit >> (cmd->scan_begin_arg - - (16 * group))) - == 1 - && cmd->scan_begin_src == - TRIG_EXT) { - DEBUG - ("s626_irq_handler: Edge capture interrupt received from channel %d\n", - cmd->scan_begin_arg); - - /* Trigger ADC scan loop start by setting RPS Signal 0. */ - MC_ENABLE(P_MC2, MC2_ADC_RPS); - - DEBUG - ("s626_irq_handler: scan triggered!!! %d\n", - devpriv->ai_sample_count); - if (cmd->convert_src == - TRIG_EXT) { - - DEBUG - ("s626_ai_cmd: enable interrupt on dio channel %d group %d\n", - cmd->convert_arg - - (16 * group), - group); - - devpriv->ai_convert_count - = cmd->chanlist_len; - - s626_dio_set_irq(dev, - cmd->convert_arg); - - DEBUG - ("s626_irq_handler: External convert trigger is set!!!\n"); - } - - if (cmd->convert_src == - TRIG_TIMER) { - k = &encpriv[5]; - devpriv->ai_convert_count - = cmd->chanlist_len; - k->SetEnable(dev, k, - CLKENAB_ALWAYS); - } - } - if ((irqbit >> (cmd->convert_arg - - (16 * group))) - == 1 - && cmd->convert_src == TRIG_EXT) { - DEBUG - ("s626_irq_handler: Edge capture interrupt received from channel %d\n", - cmd->convert_arg); - - /* Trigger ADC scan loop start by setting RPS Signal 0. */ - MC_ENABLE(P_MC2, MC2_ADC_RPS); - - DEBUG - ("s626_irq_handler: adc convert triggered!!!\n"); - - devpriv->ai_convert_count--; - - if (devpriv->ai_convert_count > - 0) { - - DEBUG - ("s626_ai_cmd: enable interrupt on dio channel %d group %d\n", - cmd->convert_arg - - (16 * group), - group); - - s626_dio_set_irq(dev, - cmd->convert_arg); - - DEBUG - ("s626_irq_handler: External trigger is set!!!\n"); - } - } - } - break; + devpriv->ai_convert_count = cmd->chanlist_len; + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); } } + if ((irqbit >> (cmd->convert_arg - (16 * group))) == 1 && + cmd->convert_src == TRIG_EXT) { + /* Trigger ADC scan loop start */ + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); + + devpriv->ai_convert_count--; + if (devpriv->ai_convert_count > 0) + s626_dio_set_irq(dev, cmd->convert_arg); + } + } +} + +static void s626_check_dio_interrupts(struct comedi_device *dev) +{ + uint16_t irqbit; + uint8_t group; + for (group = 0; group < S626_DIO_BANKS; group++) { + irqbit = 0; /* read interrupt type */ - irqbit = DEBIread(dev, LP_RDMISC2); + irqbit = s626_debi_read(dev, S626_LP_RDCAPFLG(group)); - /* check interrupt on counters */ - DEBUG("s626_irq_handler: check counters interrupt %d\n", - irqbit); + /* check if interrupt is generated from dio channels */ + if (irqbit) { + s626_handle_dio_interrupt(dev, irqbit, group); + return; + } + } +} - if (irqbit & IRQ_COINT1A) { - DEBUG - ("s626_irq_handler: interrupt on counter 1A overflow\n"); - k = &encpriv[0]; +static void s626_check_counter_interrupts(struct comedi_device *dev) +{ + struct s626_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + const struct s626_enc_info *k; + uint16_t irqbit; - /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); - } - if (irqbit & IRQ_COINT2A) { - DEBUG - ("s626_irq_handler: interrupt on counter 2A overflow\n"); - k = &encpriv[1]; + /* read interrupt type */ + irqbit = s626_debi_read(dev, S626_LP_RDMISC2); - /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); - } - if (irqbit & IRQ_COINT3A) { - DEBUG - ("s626_irq_handler: interrupt on counter 3A overflow\n"); - k = &encpriv[2]; + /* check interrupt on counters */ + if (irqbit & S626_IRQ_COINT1A) { + k = &s626_enc_chan_info[0]; - /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); - } - if (irqbit & IRQ_COINT1B) { - DEBUG - ("s626_irq_handler: interrupt on counter 1B overflow\n"); - k = &encpriv[3]; + /* clear interrupt capture flag */ + k->reset_cap_flags(dev, k); + } + if (irqbit & S626_IRQ_COINT2A) { + k = &s626_enc_chan_info[1]; - /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); - } - if (irqbit & IRQ_COINT2B) { - DEBUG - ("s626_irq_handler: interrupt on counter 2B overflow\n"); - k = &encpriv[4]; - - /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); - - if (devpriv->ai_convert_count > 0) { - devpriv->ai_convert_count--; - if (devpriv->ai_convert_count == 0) - k->SetEnable(dev, k, CLKENAB_INDEX); - - if (cmd->convert_src == TRIG_TIMER) { - DEBUG - ("s626_irq_handler: conver timer trigger!!! %d\n", - devpriv->ai_convert_count); - - /* Trigger ADC scan loop start by setting RPS Signal 0. */ - MC_ENABLE(P_MC2, MC2_ADC_RPS); - } - } - } - if (irqbit & IRQ_COINT3B) { - DEBUG - ("s626_irq_handler: interrupt on counter 3B overflow\n"); - k = &encpriv[5]; + /* clear interrupt capture flag */ + k->reset_cap_flags(dev, k); + } + if (irqbit & S626_IRQ_COINT3A) { + k = &s626_enc_chan_info[2]; - /* clear interrupt capture flag */ - k->ResetCapFlags(dev, k); + /* clear interrupt capture flag */ + k->reset_cap_flags(dev, k); + } + if (irqbit & S626_IRQ_COINT1B) { + k = &s626_enc_chan_info[3]; - if (cmd->scan_begin_src == TRIG_TIMER) { - DEBUG - ("s626_irq_handler: scan timer trigger!!!\n"); + /* clear interrupt capture flag */ + k->reset_cap_flags(dev, k); + } + if (irqbit & S626_IRQ_COINT2B) { + k = &s626_enc_chan_info[4]; - /* Trigger ADC scan loop start by setting RPS Signal 0. */ - MC_ENABLE(P_MC2, MC2_ADC_RPS); - } + /* clear interrupt capture flag */ + k->reset_cap_flags(dev, k); + + if (devpriv->ai_convert_count > 0) { + devpriv->ai_convert_count--; + if (devpriv->ai_convert_count == 0) + k->set_enable(dev, k, S626_CLKENAB_INDEX); if (cmd->convert_src == TRIG_TIMER) { - DEBUG - ("s626_irq_handler: convert timer trigger is set\n"); - k = &encpriv[4]; - devpriv->ai_convert_count = cmd->chanlist_len; - k->SetEnable(dev, k, CLKENAB_ALWAYS); + /* Trigger ADC scan loop start */ + s626_mc_enable(dev, S626_MC2_ADC_RPS, + S626_P_MC2); } } } + if (irqbit & S626_IRQ_COINT3B) { + k = &s626_enc_chan_info[5]; - /* enable interrupt */ - writel(irqstatus, devpriv->base_addr + P_IER); + /* clear interrupt capture flag */ + k->reset_cap_flags(dev, k); - DEBUG("s626_irq_handler: exit interrupt service routine.\n"); + if (cmd->scan_begin_src == TRIG_TIMER) { + /* Trigger ADC scan loop start */ + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); + } - spin_unlock_irqrestore(&dev->spinlock, flags); - return IRQ_HANDLED; + if (cmd->convert_src == TRIG_TIMER) { + k = &s626_enc_chan_info[4]; + devpriv->ai_convert_count = cmd->chanlist_len; + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); + } + } } -static int s626_detach(struct comedi_device *dev) +static bool s626_handle_eos_interrupt(struct comedi_device *dev) { - if (devpriv) { - /* stop ai_command */ + struct s626_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + /* + * Init ptr to DMA buffer that holds new ADC data. We skip the + * first uint16_t in the buffer because it contains junk data + * from the final ADC of the previous poll list scan. + */ + uint32_t *readaddr = (uint32_t *)devpriv->ana_buf.logical_base + 1; + bool finished = false; + int i; + + /* get the data and hand it over to comedi */ + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned short tempdata; + + /* + * Convert ADC data to 16-bit integer values and copy + * to application buffer. + */ + tempdata = s626_ai_reg_to_uint(*readaddr); + readaddr++; + + /* put data into read buffer */ + cfc_write_to_buffer(s, tempdata); + } + + /* end of scan occurs */ + async->events |= COMEDI_CB_EOS; + + if (!devpriv->ai_continuous) + devpriv->ai_sample_count--; + if (devpriv->ai_sample_count <= 0) { devpriv->ai_cmd_running = 0; - if (devpriv->base_addr) { - /* interrupt mask */ - WR7146(P_IER, 0); /* Disable master interrupt. */ - WR7146(P_ISR, IRQ_GPIO3 | IRQ_RPS1); /* Clear board's IRQ status flag. */ + /* Stop RPS program */ + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); - /* Disable the watchdog timer and battery charger. */ - WriteMISC2(dev, 0); + /* send end of acquisition */ + async->events |= COMEDI_CB_EOA; - /* Close all interfaces on 7146 device. */ - WR7146(P_MC1, MC1_SHUTDOWN); - WR7146(P_ACON1, ACON1_BASE); + /* disable master interrupt */ + finished = true; + } - CloseDMAB(dev, &devpriv->RPSBuf, DMABUF_SIZE); - CloseDMAB(dev, &devpriv->ANABuf, DMABUF_SIZE); - } + if (devpriv->ai_cmd_running && cmd->scan_begin_src == TRIG_EXT) + s626_dio_set_irq(dev, cmd->scan_begin_arg); - if (dev->irq) - free_irq(dev->irq, dev); + /* tell comedi that data is there */ + comedi_event(dev, s); - if (devpriv->base_addr) - iounmap(devpriv->base_addr); + return finished; +} - if (devpriv->pdev) { - if (devpriv->got_regions) - comedi_pci_disable(devpriv->pdev); - pci_dev_put(devpriv->pdev); - } +static irqreturn_t s626_irq_handler(int irq, void *d) +{ + struct comedi_device *dev = d; + struct s626_private *devpriv = dev->private; + unsigned long flags; + uint32_t irqtype, irqstatus; + + if (!dev->attached) + return IRQ_NONE; + /* lock to avoid race with comedi_poll */ + spin_lock_irqsave(&dev->spinlock, flags); + + /* save interrupt enable register state */ + irqstatus = readl(devpriv->mmio + S626_P_IER); + + /* read interrupt type */ + irqtype = readl(devpriv->mmio + S626_P_ISR); + + /* disable master interrupt */ + writel(0, devpriv->mmio + S626_P_IER); + + /* clear interrupt */ + writel(irqtype, devpriv->mmio + S626_P_ISR); + + switch (irqtype) { + case S626_IRQ_RPS1: /* end_of_scan occurs */ + if (s626_handle_eos_interrupt(dev)) + irqstatus = 0; + break; + case S626_IRQ_GPIO3: /* check dio and counter interrupt */ + /* s626_dio_clear_irq(dev); */ + s626_check_dio_interrupts(dev); + s626_check_counter_interrupts(dev); + break; } - DEBUG("s626_detach: S626 detached!\n"); + /* enable interrupt */ + writel(irqstatus, devpriv->mmio + S626_P_IER); - return 0; + spin_unlock_irqrestore(&dev->spinlock, flags); + return IRQ_HANDLED; } /* - * this functions build the RPS program for hardware driven acquistion + * This function builds the RPS program for hardware driven acquisition. */ -void ResetADC(struct comedi_device *dev, uint8_t * ppl) +static void s626_reset_adc(struct comedi_device *dev, uint8_t *ppl) { - register uint32_t *pRPS; - uint32_t JmpAdrs; + struct s626_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + uint32_t *rps; + uint32_t jmp_adrs; uint16_t i; uint16_t n; - uint32_t LocalPPL; - struct comedi_cmd *cmd = &(dev->subdevices->async->cmd); + uint32_t local_ppl; - /* Stop RPS program in case it is currently running. */ - MC_DISABLE(P_MC1, MC1_ERPS1); + /* Stop RPS program in case it is currently running */ + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); - /* Set starting logical address to write RPS commands. */ - pRPS = (uint32_t *) devpriv->RPSBuf.LogicalBase; + /* Set starting logical address to write RPS commands. */ + rps = (uint32_t *)devpriv->rps_buf.logical_base; - /* Initialize RPS instruction pointer. */ - WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase); - - /* Construct RPS program in RPSBuf DMA buffer */ + /* Initialize RPS instruction pointer */ + writel((uint32_t)devpriv->rps_buf.physical_base, + devpriv->mmio + S626_P_RPSADDR1); + /* Construct RPS program in rps_buf DMA buffer */ if (cmd != NULL && cmd->scan_begin_src != TRIG_FOLLOW) { - DEBUG("ResetADC: scan_begin pause inserted\n"); - /* Wait for Start trigger. */ - *pRPS++ = RPS_PAUSE | RPS_SIGADC; - *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC; + /* Wait for Start trigger. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_SIGADC; + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; } - /* SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary + /* + * SAA7146 BUG WORKAROUND Do a dummy DEBI Write. This is necessary * because the first RPS DEBI Write following a non-RPS DEBI write * seems to always fail. If we don't do this dummy write, the ADC * gain might not be set to the value required for the first slot in * the poll list; the ADC gain would instead remain unchanged from * the previously programmed value. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); /* Write DEBI Write command and address to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_GSEL; + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + /* Write DEBI immediate data to shadow RAM: */ + *rps++ = S626_GSEL_BIPOLAR5V; /* arbitrary immediate data value. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Reset "shadow RAM uploaded" flag. */ + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; - *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); - /* Write DEBI immediate data to shadow RAM: */ - - *pRPS++ = GSEL_BIPOLAR5V; - /* arbitrary immediate data value. */ - - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; - /* Reset "shadow RAM uploaded" flag. */ - *pRPS++ = RPS_UPLOAD | RPS_DEBI; /* Invoke shadow RAM upload. */ - *pRPS++ = RPS_PAUSE | RPS_DEBI; /* Wait for shadow upload to finish. */ - - /* Digitize all slots in the poll list. This is implemented as a + /* + * Digitize all slots in the poll list. This is implemented as a * for loop to limit the slot count to 16 in case the application - * forgot to set the EOPL flag in the final slot. + * forgot to set the S626_EOPL flag in the final slot. */ - for (devpriv->AdcItems = 0; devpriv->AdcItems < 16; devpriv->AdcItems++) { - /* Convert application's poll list item to private board class + for (devpriv->adc_items = 0; devpriv->adc_items < 16; + devpriv->adc_items++) { + /* + * Convert application's poll list item to private board class * format. Each app poll list item is an uint8_t with form * (EOPL,x,x,RANGE,CHAN<3:0>), where RANGE code indicates 0 = * +-10V, 1 = +-5V, and EOPL = End of Poll List marker. */ - LocalPPL = - (*ppl << 8) | (*ppl & 0x10 ? GSEL_BIPOLAR5V : - GSEL_BIPOLAR10V); - - /* Switch ADC analog gain. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); /* Write DEBI command */ - /* and address to */ - /* shadow RAM. */ - *pRPS++ = DEBI_CMD_WRWORD | LP_GSEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); /* Write DEBI */ - /* immediate data to */ - /* shadow RAM. */ - *pRPS++ = LocalPPL; - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; /* Reset "shadow RAM uploaded" */ - /* flag. */ - *pRPS++ = RPS_UPLOAD | RPS_DEBI; /* Invoke shadow RAM upload. */ - *pRPS++ = RPS_PAUSE | RPS_DEBI; /* Wait for shadow upload to */ - /* finish. */ - - /* Select ADC analog input channel. */ - *pRPS++ = RPS_LDREG | (P_DEBICMD >> 2); - /* Write DEBI command and address to shadow RAM. */ - *pRPS++ = DEBI_CMD_WRWORD | LP_ISEL; - *pRPS++ = RPS_LDREG | (P_DEBIAD >> 2); - /* Write DEBI immediate data to shadow RAM. */ - *pRPS++ = LocalPPL; - *pRPS++ = RPS_CLRSIGNAL | RPS_DEBI; - /* Reset "shadow RAM uploaded" flag. */ - - *pRPS++ = RPS_UPLOAD | RPS_DEBI; - /* Invoke shadow RAM upload. */ - - *pRPS++ = RPS_PAUSE | RPS_DEBI; - /* Wait for shadow upload to finish. */ - - /* Delay at least 10 microseconds for analog input settling. - * Instead of padding with NOPs, we use RPS_JUMP instructions - * here; this allows us to produce a longer delay than is - * possible with NOPs because each RPS_JUMP flushes the RPS' - * instruction prefetch pipeline. + local_ppl = (*ppl << 8) | (*ppl & 0x10 ? S626_GSEL_BIPOLAR5V : + S626_GSEL_BIPOLAR10V); + + /* Switch ADC analog gain. */ + /* Write DEBI command and address to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_GSEL; + /* Write DEBI immediate data to shadow RAM. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + *rps++ = local_ppl; + /* Reset "shadow RAM uploaded" flag. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; + /* Select ADC analog input channel. */ + *rps++ = S626_RPS_LDREG | (S626_P_DEBICMD >> 2); + /* Write DEBI command and address to shadow RAM. */ + *rps++ = S626_DEBI_CMD_WRWORD | S626_LP_ISEL; + *rps++ = S626_RPS_LDREG | (S626_P_DEBIAD >> 2); + /* Write DEBI immediate data to shadow RAM. */ + *rps++ = local_ppl; + /* Reset "shadow RAM uploaded" flag. */ + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_DEBI; + /* Invoke shadow RAM upload. */ + *rps++ = S626_RPS_UPLOAD | S626_RPS_DEBI; + /* Wait for shadow upload to finish. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_DEBI; + + /* + * Delay at least 10 microseconds for analog input settling. + * Instead of padding with NOPs, we use S626_RPS_JUMP + * instructions here; this allows us to produce a longer delay + * than is possible with NOPs because each S626_RPS_JUMP + * flushes the RPS' instruction prefetch pipeline. */ - JmpAdrs = - (uint32_t) devpriv->RPSBuf.PhysicalBase + - (uint32_t) ((unsigned long)pRPS - - (unsigned long)devpriv->RPSBuf.LogicalBase); - for (i = 0; i < (10 * RPSCLK_PER_US / 2); i++) { - JmpAdrs += 8; /* Repeat to implement time delay: */ - *pRPS++ = RPS_JUMP; /* Jump to next RPS instruction. */ - *pRPS++ = JmpAdrs; + jmp_adrs = + (uint32_t)devpriv->rps_buf.physical_base + + (uint32_t)((unsigned long)rps - + (unsigned long)devpriv-> + rps_buf.logical_base); + for (i = 0; i < (10 * S626_RPSCLK_PER_US / 2); i++) { + jmp_adrs += 8; /* Repeat to implement time delay: */ + /* Jump to next RPS instruction. */ + *rps++ = S626_RPS_JUMP; + *rps++ = jmp_adrs; } if (cmd != NULL && cmd->convert_src != TRIG_NOW) { - DEBUG("ResetADC: convert pause inserted\n"); - /* Wait for Start trigger. */ - *pRPS++ = RPS_PAUSE | RPS_SIGADC; - *pRPS++ = RPS_CLRSIGNAL | RPS_SIGADC; + /* Wait for Start trigger. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_SIGADC; + *rps++ = S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; } - /* Start ADC by pulsing GPIO1. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* Begin ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_LO; - *pRPS++ = RPS_NOP; - /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* End ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_HI; - - /* Wait for ADC to complete (GPIO2 is asserted high when ADC not + /* Start ADC by pulsing GPIO1. */ + /* Begin ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_LO; + *rps++ = S626_RPS_NOP; + /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ + /* End ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_HI; + /* + * Wait for ADC to complete (GPIO2 is asserted high when ADC not * busy) and for data from previous conversion to shift into FB * BUFFER 1 register. */ - *pRPS++ = RPS_PAUSE | RPS_GPIO2; /* Wait for ADC done. */ - - /* Transfer ADC data from FB BUFFER 1 register to DMA buffer. */ - *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2); - *pRPS++ = - (uint32_t) devpriv->ANABuf.PhysicalBase + - (devpriv->AdcItems << 2); - - /* If this slot's EndOfPollList flag is set, all channels have */ - /* now been processed. */ - if (*ppl++ & EOPL) { - devpriv->AdcItems++; /* Adjust poll list item count. */ - break; /* Exit poll list processing loop. */ + /* Wait for ADC done. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_GPIO2; + + /* Transfer ADC data from FB BUFFER 1 register to DMA buffer. */ + *rps++ = S626_RPS_STREG | + (S626_BUGFIX_STREG(S626_P_FB_BUFFER1) >> 2); + *rps++ = (uint32_t)devpriv->ana_buf.physical_base + + (devpriv->adc_items << 2); + + /* + * If this slot's EndOfPollList flag is set, all channels have + * now been processed. + */ + if (*ppl++ & S626_EOPL) { + devpriv->adc_items++; /* Adjust poll list item count. */ + break; /* Exit poll list processing loop. */ } } - DEBUG("ResetADC: ADC items %d\n", devpriv->AdcItems); - /* VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the + /* + * VERSION 2.01 CHANGE: DELAY CHANGED FROM 250NS to 2US. Allow the * ADC to stabilize for 2 microseconds before starting the final * (dummy) conversion. This delay is necessary to allow sufficient * time between last conversion finished and the start of the dummy * conversion. Without this delay, the last conversion's data value * is sometimes set to the previous conversion's data value. */ - for (n = 0; n < (2 * RPSCLK_PER_US); n++) - *pRPS++ = RPS_NOP; + for (n = 0; n < (2 * S626_RPSCLK_PER_US); n++) + *rps++ = S626_RPS_NOP; - /* Start a dummy conversion to cause the data from the last + /* + * Start a dummy conversion to cause the data from the last * conversion of interest to be shifted in. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* Begin ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_LO; - *pRPS++ = RPS_NOP; + /* Begin ADC Start pulse. */ + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); + *rps++ = S626_GPIO_BASE | S626_GPIO1_LO; + *rps++ = S626_RPS_NOP; /* VERSION 2.03 CHANGE: STRETCH OUT ADC START PULSE. */ - *pRPS++ = RPS_LDREG | (P_GPIO >> 2); /* End ADC Start pulse. */ - *pRPS++ = GPIO_BASE | GPIO1_HI; + *rps++ = S626_RPS_LDREG | (S626_P_GPIO >> 2); /* End ADC Start pulse. */ + *rps++ = S626_GPIO_BASE | S626_GPIO1_HI; - /* Wait for the data from the last conversion of interest to arrive + /* + * Wait for the data from the last conversion of interest to arrive * in FB BUFFER 1 register. */ - *pRPS++ = RPS_PAUSE | RPS_GPIO2; /* Wait for ADC done. */ + *rps++ = S626_RPS_PAUSE | S626_RPS_GPIO2; /* Wait for ADC done. */ - /* Transfer final ADC data from FB BUFFER 1 register to DMA buffer. */ - *pRPS++ = RPS_STREG | (BUGFIX_STREG(P_FB_BUFFER1) >> 2); /* */ - *pRPS++ = - (uint32_t) devpriv->ANABuf.PhysicalBase + (devpriv->AdcItems << 2); + /* Transfer final ADC data from FB BUFFER 1 register to DMA buffer. */ + *rps++ = S626_RPS_STREG | (S626_BUGFIX_STREG(S626_P_FB_BUFFER1) >> 2); + *rps++ = (uint32_t)devpriv->ana_buf.physical_base + + (devpriv->adc_items << 2); - /* Indicate ADC scan loop is finished. */ - /* *pRPS++= RPS_CLRSIGNAL | RPS_SIGADC ; // Signal ReadADC() that scan is done. */ + /* Indicate ADC scan loop is finished. */ + /* Signal ReadADC() that scan is done. */ + /* *rps++= S626_RPS_CLRSIGNAL | S626_RPS_SIGADC; */ /* invoke interrupt */ - if (devpriv->ai_cmd_running == 1) { - DEBUG("ResetADC: insert irq in ADC RPS task\n"); - *pRPS++ = RPS_IRQ; - } - /* Restart RPS program at its beginning. */ - *pRPS++ = RPS_JUMP; /* Branch to start of RPS program. */ - *pRPS++ = (uint32_t) devpriv->RPSBuf.PhysicalBase; + if (devpriv->ai_cmd_running == 1) + *rps++ = S626_RPS_IRQ; + + /* Restart RPS program at its beginning. */ + *rps++ = S626_RPS_JUMP; /* Branch to start of RPS program. */ + *rps++ = (uint32_t)devpriv->rps_buf.physical_base; - /* End of RPS program build */ + /* End of RPS program build */ } -/* TO COMPLETE, IF NECESSARY */ -static int s626_ai_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +#ifdef unused_code +static int s626_ai_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct s626_private *devpriv = dev->private; + uint8_t i; + int32_t *readaddr; - return -EINVAL; -} - -/* static int s626_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data) */ -/* { */ -/* register uint8_t i; */ -/* register int32_t *readaddr; */ + /* Trigger ADC scan loop start */ + s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); -/* DEBUG("as626_ai_rinsn: ai_rinsn enter\n"); */ + /* Wait until ADC scan loop is finished (RPS Signal 0 reset) */ + while (s626_mc_test(dev, S626_MC2_ADC_RPS, S626_P_MC2)) + ; -/* Trigger ADC scan loop start by setting RPS Signal 0. */ -/* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */ + /* + * Init ptr to DMA buffer that holds new ADC data. We skip the + * first uint16_t in the buffer because it contains junk data from + * the final ADC of the previous poll list scan. + */ + readaddr = (uint32_t *)devpriv->ana_buf.logical_base + 1; -/* Wait until ADC scan loop is finished (RPS Signal 0 reset). */ -/* while ( MC_TEST( P_MC2, MC2_ADC_RPS ) ); */ + /* + * Convert ADC data to 16-bit integer values and + * copy to application buffer. + */ + for (i = 0; i < devpriv->adc_items; i++) { + *data = s626_ai_reg_to_uint(*readaddr++); + data++; + } -/* Init ptr to DMA buffer that holds new ADC data. We skip the - * first uint16_t in the buffer because it contains junk data from - * the final ADC of the previous poll list scan. - */ -/* readaddr = (uint32_t *)devpriv->ANABuf.LogicalBase + 1; */ + return i; +} +#endif -/* Convert ADC data to 16-bit integer values and copy to application buffer. */ -/* for ( i = 0; i < devpriv->AdcItems; i++ ) { */ -/* *data = s626_ai_reg_to_uint( *readaddr++ ); */ -/* DEBUG("s626_ai_rinsn: data %d\n",*data); */ -/* data++; */ -/* } */ +static int s626_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) +{ + struct s626_private *devpriv = dev->private; + unsigned int status; -/* DEBUG("s626_ai_rinsn: ai_rinsn escape\n"); */ -/* return i; */ -/* } */ + status = readl(devpriv->mmio + S626_P_PSR); + if (status & S626_PSR_GPIO2) + return 0; + return -EBUSY; +} static int s626_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct s626_private *devpriv = dev->private; uint16_t chan = CR_CHAN(insn->chanspec); uint16_t range = CR_RANGE(insn->chanspec); - uint16_t AdcSpec = 0; - uint32_t GpioImage; + uint16_t adc_spec = 0; + uint32_t gpio_image; + uint32_t tmp; + int ret; int n; - /* interrupt call test */ -/* writel(IRQ_GPIO3,devpriv->base_addr+P_PSR); */ - /* Writing a logical 1 into any of the RPS_PSR bits causes the - * corresponding interrupt to be generated if enabled - */ - - DEBUG("s626_ai_insn_read: entering\n"); - - /* Convert application's ADC specification into form + /* + * Convert application's ADC specification into form * appropriate for register programming. */ if (range == 0) - AdcSpec = (chan << 8) | (GSEL_BIPOLAR5V); + adc_spec = (chan << 8) | (S626_GSEL_BIPOLAR5V); else - AdcSpec = (chan << 8) | (GSEL_BIPOLAR10V); + adc_spec = (chan << 8) | (S626_GSEL_BIPOLAR10V); - /* Switch ADC analog gain. */ - DEBIwrite(dev, LP_GSEL, AdcSpec); /* Set gain. */ + /* Switch ADC analog gain. */ + s626_debi_write(dev, S626_LP_GSEL, adc_spec); /* Set gain. */ - /* Select ADC analog input channel. */ - DEBIwrite(dev, LP_ISEL, AdcSpec); /* Select channel. */ + /* Select ADC analog input channel. */ + s626_debi_write(dev, S626_LP_ISEL, adc_spec); /* Select channel. */ for (n = 0; n < insn->n; n++) { - - /* Delay 10 microseconds for analog input settling. */ + /* Delay 10 microseconds for analog input settling. */ udelay(10); - /* Start ADC by pulsing GPIO1 low. */ - GpioImage = RR7146(P_GPIO); - /* Assert ADC Start command */ - WR7146(P_GPIO, GpioImage & ~GPIO1_HI); - /* and stretch it out. */ - WR7146(P_GPIO, GpioImage & ~GPIO1_HI); - WR7146(P_GPIO, GpioImage & ~GPIO1_HI); - /* Negate ADC Start command. */ - WR7146(P_GPIO, GpioImage | GPIO1_HI); - - /* Wait for ADC to complete (GPIO2 is asserted high when */ - /* ADC not busy) and for data from previous conversion to */ - /* shift into FB BUFFER 1 register. */ - - /* Wait for ADC done. */ - while (!(RR7146(P_PSR) & PSR_GPIO2)) - ; - - /* Fetch ADC data. */ - if (n != 0) - data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1)); - - /* Allow the ADC to stabilize for 4 microseconds before + /* Start ADC by pulsing GPIO1 low */ + gpio_image = readl(devpriv->mmio + S626_P_GPIO); + /* Assert ADC Start command */ + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); + /* and stretch it out */ + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, + devpriv->mmio + S626_P_GPIO); + /* Negate ADC Start command */ + writel(gpio_image | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); + + /* + * Wait for ADC to complete (GPIO2 is asserted high when + * ADC not busy) and for data from previous conversion to + * shift into FB BUFFER 1 register. + */ + + /* Wait for ADC done */ + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; + + /* Fetch ADC data */ + if (n != 0) { + tmp = readl(devpriv->mmio + S626_P_FB_BUFFER1); + data[n - 1] = s626_ai_reg_to_uint(tmp); + } + + /* + * Allow the ADC to stabilize for 4 microseconds before * starting the next (final) conversion. This delay is * necessary to allow sufficient time between last * conversion finished and the start of the next @@ -1707,112 +2027,171 @@ static int s626_ai_insn_read(struct comedi_device *dev, udelay(4); } - /* Start a dummy conversion to cause the data from the - * previous conversion to be shifted in. */ - GpioImage = RR7146(P_GPIO); - + /* + * Start a dummy conversion to cause the data from the + * previous conversion to be shifted in. + */ + gpio_image = readl(devpriv->mmio + S626_P_GPIO); /* Assert ADC Start command */ - WR7146(P_GPIO, GpioImage & ~GPIO1_HI); - /* and stretch it out. */ - WR7146(P_GPIO, GpioImage & ~GPIO1_HI); - WR7146(P_GPIO, GpioImage & ~GPIO1_HI); - /* Negate ADC Start command. */ - WR7146(P_GPIO, GpioImage | GPIO1_HI); - - /* Wait for the data to arrive in FB BUFFER 1 register. */ - - /* Wait for ADC done. */ - while (!(RR7146(P_PSR) & PSR_GPIO2)) - ; - - /* Fetch ADC data from audio interface's input shift register. */ - - /* Fetch ADC data. */ - if (n != 0) - data[n - 1] = s626_ai_reg_to_uint(RR7146(P_FB_BUFFER1)); - - DEBUG("s626_ai_insn_read: samples %d, data %d\n", n, data[n - 1]); + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); + /* and stretch it out */ + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); + writel(gpio_image & ~S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); + /* Negate ADC Start command */ + writel(gpio_image | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); + + /* Wait for the data to arrive in FB BUFFER 1 register. */ + + /* Wait for ADC done */ + ret = comedi_timeout(dev, s, insn, s626_ai_eoc, 0); + if (ret) + return ret; + + /* Fetch ADC data from audio interface's input shift register. */ + + /* Fetch ADC data */ + if (n != 0) { + tmp = readl(devpriv->mmio + S626_P_FB_BUFFER1); + data[n - 1] = s626_ai_reg_to_uint(tmp); + } return n; } static int s626_ai_load_polllist(uint8_t *ppl, struct comedi_cmd *cmd) { - int n; for (n = 0; n < cmd->chanlist_len; n++) { - if (CR_RANGE((cmd->chanlist)[n]) == 0) - ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_5V); + if (CR_RANGE(cmd->chanlist[n]) == 0) + ppl[n] = CR_CHAN(cmd->chanlist[n]) | S626_RANGE_5V; else - ppl[n] = (CR_CHAN((cmd->chanlist)[n])) | (RANGE_10V); + ppl[n] = CR_CHAN(cmd->chanlist[n]) | S626_RANGE_10V; } if (n != 0) - ppl[n - 1] |= EOPL; + ppl[n - 1] |= S626_EOPL; return n; } static int s626_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { - if (trignum != 0) - return -EINVAL; + struct comedi_cmd *cmd = &s->async->cmd; - DEBUG("s626_ai_inttrig: trigger adc start..."); + if (trig_num != cmd->start_arg) + return -EINVAL; - /* Start executing the RPS program. */ - MC_ENABLE(P_MC1, MC1_ERPS1); + /* Start executing the RPS program */ + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); s->async->inttrig = NULL; - DEBUG(" done\n"); - return 1; } -/* TO COMPLETE */ -static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +/* + * 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 s626_ns_to_timer(unsigned int *nanosec, int round_mode) +{ + int divider, base; + + base = 500; /* 2MHz internal clock */ + + switch (round_mode) { + case TRIG_ROUND_NEAREST: + default: + divider = (*nanosec + base / 2) / base; + break; + case TRIG_ROUND_DOWN: + divider = (*nanosec) / base; + break; + case TRIG_ROUND_UP: + divider = (*nanosec + base - 1) / base; + break; + } + + *nanosec = base * divider; + return divider - 1; +} + +static void s626_timer_load(struct comedi_device *dev, + const struct s626_enc_info *k, int tick) { + uint16_t setup = + /* Preload upon index. */ + S626_SET_STD_LOADSRC(S626_LOADSRC_INDX) | + /* Disable hardware index. */ + S626_SET_STD_INDXSRC(S626_INDXSRC_SOFT) | + /* Operating mode is Timer. */ + S626_SET_STD_ENCMODE(S626_ENCMODE_TIMER) | + /* Count direction is Down. */ + S626_SET_STD_CLKPOL(S626_CNTDIR_DOWN) | + /* Clock multiplier is 1x. */ + S626_SET_STD_CLKMULT(S626_CLKMULT_1X) | + /* Enabled by index */ + S626_SET_STD_CLKENAB(S626_CLKENAB_INDEX); + uint16_t value_latchsrc = S626_LATCHSRC_A_INDXA; + /* uint16_t enab = S626_CLKENAB_ALWAYS; */ + + k->set_mode(dev, k, setup, false); + + /* Set the preload register */ + s626_preload(dev, k, tick); + /* + * Software index pulse forces the preload register to load + * into the counter + */ + k->set_load_trig(dev, k, 0); + k->pulse_index(dev, k); + + /* set reload on counter overflow */ + k->set_load_trig(dev, k, 1); + + /* set interrupt on overflow */ + k->set_int_src(dev, k, S626_INTSRC_OVER); + + s626_set_latch_source(dev, k, value_latchsrc); + /* k->set_enable(dev, k, (uint16_t)(enab != 0)); */ +} + +/* TO COMPLETE */ +static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) +{ + struct s626_private *devpriv = dev->private; uint8_t ppl[16]; struct comedi_cmd *cmd = &s->async->cmd; - struct enc_private *k; + const struct s626_enc_info *k; int tick; - DEBUG("s626_ai_cmd: entering command function\n"); - if (devpriv->ai_cmd_running) { - printk(KERN_ERR "s626_ai_cmd: Another ai_cmd is running %d\n", - dev->minor); + dev_err(dev->class_dev, + "s626_ai_cmd: Another ai_cmd is running\n"); return -EBUSY; } /* disable interrupt */ - writel(0, devpriv->base_addr + P_IER); + writel(0, devpriv->mmio + S626_P_IER); /* clear interrupt request */ - writel(IRQ_RPS1 | IRQ_GPIO3, devpriv->base_addr + P_ISR); + writel(S626_IRQ_RPS1 | S626_IRQ_GPIO3, devpriv->mmio + S626_P_ISR); /* clear any pending interrupt */ s626_dio_clear_irq(dev); - /* s626_enc_clear_irq(dev); */ + /* s626_enc_clear_irq(dev); */ /* reset ai_cmd_running flag */ devpriv->ai_cmd_running = 0; - /* test if cmd is valid */ - if (cmd == NULL) { - DEBUG("s626_ai_cmd: NULL command\n"); + /* test if cmd is valid */ + if (cmd == NULL) return -EINVAL; - } else { - DEBUG("s626_ai_cmd: command received!!!\n"); - } - - if (dev->irq == 0) { - comedi_error(dev, - "s626_ai_cmd: cannot run command without an irq"); - return -EIO; - } s626_ai_load_polllist(ppl, cmd); devpriv->ai_cmd_running = 1; @@ -1822,26 +2201,22 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_FOLLOW: break; case TRIG_TIMER: - /* set a conter to generate adc trigger at scan_begin_arg interval */ - k = &encpriv[5]; - tick = s626_ns_to_timer((int *)&cmd->scan_begin_arg, + /* + * set a counter to generate adc trigger at scan_begin_arg + * interval + */ + k = &s626_enc_chan_info[5]; + tick = s626_ns_to_timer(&cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); /* load timer value and enable interrupt */ s626_timer_load(dev, k, tick); - k->SetEnable(dev, k, CLKENAB_ALWAYS); - - DEBUG("s626_ai_cmd: scan trigger timer is set with value %d\n", - tick); - + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); break; case TRIG_EXT: - /* set the digital line and interrupt for scan trigger */ + /* set the digital line and interrupt for scan trigger */ if (cmd->start_src != TRIG_EXT) s626_dio_set_irq(dev, cmd->scan_begin_arg); - - DEBUG("s626_ai_cmd: External scan trigger is set!!!\n"); - break; } @@ -1849,62 +2224,53 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) case TRIG_NOW: break; case TRIG_TIMER: - /* set a conter to generate adc trigger at convert_arg interval */ - k = &encpriv[4]; - tick = s626_ns_to_timer((int *)&cmd->convert_arg, + /* + * set a counter to generate adc trigger at convert_arg + * interval + */ + k = &s626_enc_chan_info[4]; + tick = s626_ns_to_timer(&cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); /* load timer value and enable interrupt */ s626_timer_load(dev, k, tick); - k->SetEnable(dev, k, CLKENAB_INDEX); - - DEBUG - ("s626_ai_cmd: convert trigger timer is set with value %d\n", - tick); + k->set_enable(dev, k, S626_CLKENAB_INDEX); break; case TRIG_EXT: - /* set the digital line and interrupt for convert trigger */ - if (cmd->scan_begin_src != TRIG_EXT - && cmd->start_src == TRIG_EXT) + /* set the digital line and interrupt for convert trigger */ + if (cmd->scan_begin_src != TRIG_EXT && + cmd->start_src == TRIG_EXT) s626_dio_set_irq(dev, cmd->convert_arg); - - DEBUG("s626_ai_cmd: External convert trigger is set!!!\n"); - break; } switch (cmd->stop_src) { case TRIG_COUNT: - /* data arrives as one packet */ + /* data arrives as one packet */ devpriv->ai_sample_count = cmd->stop_arg; - devpriv->ai_continous = 0; + devpriv->ai_continuous = 0; break; case TRIG_NONE: - /* continous acquisition */ - devpriv->ai_continous = 1; - devpriv->ai_sample_count = 0; + /* continuous acquisition */ + devpriv->ai_continuous = 1; + devpriv->ai_sample_count = 1; break; } - ResetADC(dev, ppl); + s626_reset_adc(dev, ppl); switch (cmd->start_src) { case TRIG_NOW: - /* Trigger ADC scan loop start by setting RPS Signal 0. */ - /* MC_ENABLE( P_MC2, MC2_ADC_RPS ); */ - - /* Start executing the RPS program. */ - MC_ENABLE(P_MC1, MC1_ERPS1); + /* Trigger ADC scan loop start */ + /* s626_mc_enable(dev, S626_MC2_ADC_RPS, S626_P_MC2); */ - DEBUG("s626_ai_cmd: ADC triggered\n"); + /* Start executing the RPS program */ + s626_mc_enable(dev, S626_MC1_ERPS1, S626_P_MC1); s->async->inttrig = NULL; break; case TRIG_EXT: /* configure DIO channel for acquisition trigger */ s626_dio_set_irq(dev, cmd->start_arg); - - DEBUG("s626_ai_cmd: External start trigger is set!!!\n"); - s->async->inttrig = NULL; break; case TRIG_INT: @@ -1913,9 +2279,7 @@ static int s626_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } /* enable interrupt */ - writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->base_addr + P_IER); - - DEBUG("s626_ai_cmd: command function terminated\n"); + writel(S626_IRQ_GPIO3 | S626_IRQ_RPS1, devpriv->mmio + S626_P_IER); return 0; } @@ -1924,138 +2288,82 @@ static int s626_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* 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. */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + unsigned int arg; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_EXT | TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - compatible */ + /* 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); - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT - && cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src != TRIG_EXT && cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } - - if (cmd->start_src == TRIG_EXT && cmd->start_arg > 39) { - cmd->start_arg = 39; - err++; + switch (cmd->start_src) { + case TRIG_NOW: + case TRIG_INT: + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + break; + case TRIG_EXT: + err |= cfc_check_trigger_arg_max(&cmd->start_arg, 39); + break; } - if (cmd->scan_begin_src == TRIG_EXT && cmd->scan_begin_arg > 39) { - cmd->scan_begin_arg = 39; - err++; - } + if (cmd->scan_begin_src == TRIG_EXT) + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 39); + if (cmd->convert_src == TRIG_EXT) + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 39); - if (cmd->convert_src == TRIG_EXT && cmd->convert_arg > 39) { - cmd->convert_arg = 39; - err++; - } -#define MAX_SPEED 200000 /* in nanoseconds */ -#define MIN_SPEED 2000000000 /* in nanoseconds */ +#define S626_MAX_SPEED 200000 /* in nanoseconds */ +#define S626_MIN_SPEED 2000000000 /* in nanoseconds */ if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < MAX_SPEED) { - cmd->scan_begin_arg = MAX_SPEED; - err++; - } - if (cmd->scan_begin_arg > MIN_SPEED) { - cmd->scan_begin_arg = MIN_SPEED; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + S626_MAX_SPEED); + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, + S626_MIN_SPEED); } else { /* external trigger */ /* should be level/edge, hi/lo specification here */ /* should specify multiple external triggers */ -/* if(cmd->scan_begin_arg>9){ */ -/* cmd->scan_begin_arg=9; */ -/* err++; */ -/* } */ + /* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ } if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < MAX_SPEED) { - cmd->convert_arg = MAX_SPEED; - err++; - } - if (cmd->convert_arg > MIN_SPEED) { - cmd->convert_arg = MIN_SPEED; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, + S626_MAX_SPEED); + err |= cfc_check_trigger_arg_max(&cmd->convert_arg, + S626_MIN_SPEED); } else { /* external trigger */ /* see above */ -/* if(cmd->convert_arg>9){ */ -/* cmd->convert_arg=9; */ -/* err++; */ -/* } */ + /* err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); */ } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg > 0x00ffffff) { - cmd->stop_arg = 0x00ffffff; - err++; - } - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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; @@ -2063,24 +2371,20 @@ static int s626_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - s626_ns_to_timer((int *)&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + s626_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } + if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - s626_ns_to_timer((int *)&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + s626_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -2092,50 +2396,25 @@ static int s626_ai_cmdtest(struct comedi_device *dev, static int s626_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - /* Stop RPS program in case it is currently running. */ - MC_DISABLE(P_MC1, MC1_ERPS1); + struct s626_private *devpriv = dev->private; + + /* Stop RPS program in case it is currently running */ + s626_mc_disable(dev, S626_MC1_ERPS1, S626_P_MC1); /* disable master interrupt */ - writel(0, devpriv->base_addr + P_IER); + writel(0, devpriv->mmio + S626_P_IER); devpriv->ai_cmd_running = 0; return 0; } -/* 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 s626_ns_to_timer(int *nanosec, int round_mode) -{ - int divider, base; - - base = 500; /* 2MHz internal clock */ - - switch (round_mode) { - case TRIG_ROUND_NEAREST: - default: - divider = (*nanosec + base / 2) / base; - break; - case TRIG_ROUND_DOWN: - divider = (*nanosec) / base; - break; - case TRIG_ROUND_UP: - divider = (*nanosec + base - 1) / base; - break; - } - - *nanosec = base * divider; - return divider - 1; -} - static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - + struct s626_private *devpriv = dev->private; int i; + int ret; uint16_t chan = CR_CHAN(insn->chanspec); int16_t dacdata; @@ -2144,7 +2423,9 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[i]; dacdata -= (0x1fff); - SetDAC(dev, chan, dacdata); + ret = s626_set_dac(dev, chan, dacdata); + if (ret) + return ret; } return i; @@ -2153,6 +2434,7 @@ static int s626_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 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++) @@ -2161,7 +2443,9 @@ static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* *************** DIGITAL I/O FUNCTIONS *************** +/* *************** DIGITAL I/O FUNCTIONS *************** */ + +/* * All DIO functions address a group of DIO channels by means of * "group" argument. group may be 0, 1 or 2, which correspond to DIO * ports A, B and C, respectively. @@ -2170,210 +2454,95 @@ static int s626_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, static void s626_dio_init(struct comedi_device *dev) { uint16_t group; - struct comedi_subdevice *s; - /* Prepare to treat writes to WRCapSel as capture disables. */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); + /* Prepare to treat writes to WRCapSel as capture disables. */ + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_NOEDCAP); - /* For each group of sixteen channels ... */ + /* For each group of sixteen channels ... */ for (group = 0; group < S626_DIO_BANKS; group++) { - s = dev->subdevices + 2 + group; - DEBIwrite(dev, diopriv->WRIntSel, 0); /* Disable all interrupts. */ - DEBIwrite(dev, diopriv->WRCapSel, 0xFFFF); /* Disable all event */ - /* captures. */ - DEBIwrite(dev, diopriv->WREdgSel, 0); /* Init all DIOs to */ - /* default edge */ - /* polarity. */ - DEBIwrite(dev, diopriv->WRDOut, 0); /* Program all outputs */ - /* to inactive state. */ + /* Disable all interrupts */ + s626_debi_write(dev, S626_LP_WRINTSEL(group), 0); + /* Disable all event captures */ + s626_debi_write(dev, S626_LP_WRCAPSEL(group), 0xffff); + /* Init all DIOs to default edge polarity */ + s626_debi_write(dev, S626_LP_WREDGSEL(group), 0); + /* Program all outputs to inactive state */ + s626_debi_write(dev, S626_LP_WRDOUT(group), 0); } - DEBUG("s626_dio_init: DIO initialized\n"); } -/* 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 s626_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + unsigned long group = (unsigned long)s->private; - /* Length of data must be 2 (mask and new data, see below) */ - if (insn->n == 0) - return 0; - - if (insn->n != 2) { - printk - ("comedi%d: s626: s626_dio_insn_bits(): Invalid instruction length\n", - dev->minor); - return -EINVAL; - } - - /* - * The insn data consists of a mask in data[0] and the new data in - * data[1]. The mask defines which bits we are concerning about. - * The new data must be anded with the mask. Each channel - * corresponds to a bit. - */ - if (data[0]) { - /* Check if requested ports are configured for output */ - if ((s->io_bits & data[0]) != data[0]) - return -EIO; - - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + if (comedi_dio_update_state(s, data)) + s626_debi_write(dev, S626_LP_WRDOUT(group), s->state); - /* Write out the new digital output lines */ + data[1] = s626_debi_read(dev, S626_LP_RDDIN(group)); - DEBIwrite(dev, diopriv->WRDOut, s->state); - } - data[1] = DEBIread(dev, diopriv->RDDIn); - - return 2; + return insn->n; } static int s626_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + unsigned long group = (unsigned long)s->private; + int ret; - switch (data[0]) { - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s-> - io_bits & (1 << CR_CHAN(insn->chanspec))) ? COMEDI_OUTPUT : - COMEDI_INPUT; - return insn->n; - break; - case COMEDI_INPUT: - s->io_bits &= ~(1 << CR_CHAN(insn->chanspec)); - break; - case COMEDI_OUTPUT: - s->io_bits |= 1 << CR_CHAN(insn->chanspec); - break; - default: - return -EINVAL; - break; - } - DEBIwrite(dev, diopriv->WRDOut, s->io_bits); - - return 1; -} - -static int s626_dio_set_irq(struct comedi_device *dev, unsigned int chan) -{ - unsigned int group; - unsigned int bitmask; - unsigned int status; - - /* select dio bank */ - group = chan / 16; - bitmask = 1 << (chan - (16 * group)); - DEBUG("s626_dio_set_irq: enable interrupt on dio channel %d group %d\n", - chan - (16 * group), group); - - /* set channel to capture positive edge */ - status = DEBIread(dev, - ((struct dio_private *)(dev->subdevices + 2 + - group)->private)->RDEdgSel); - DEBIwrite(dev, - ((struct dio_private *)(dev->subdevices + 2 + - group)->private)->WREdgSel, - bitmask | status); - - /* enable interrupt on selected channel */ - status = DEBIread(dev, - ((struct dio_private *)(dev->subdevices + 2 + - group)->private)->RDIntSel); - DEBIwrite(dev, - ((struct dio_private *)(dev->subdevices + 2 + - group)->private)->WRIntSel, - bitmask | status); - - /* enable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_EDCAP); - - /* enable edge capture on selected channel */ - status = DEBIread(dev, - ((struct dio_private *)(dev->subdevices + 2 + - group)->private)->RDCapSel); - DEBIwrite(dev, - ((struct dio_private *)(dev->subdevices + 2 + - group)->private)->WRCapSel, - bitmask | status); - - return 0; -} - -static int s626_dio_reset_irq(struct comedi_device *dev, unsigned int group, - unsigned int mask) -{ - DEBUG - ("s626_dio_reset_irq: disable interrupt on dio channel %d group %d\n", - mask, group); - - /* disable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); - - /* enable edge capture on selected channel */ - DEBIwrite(dev, - ((struct dio_private *)(dev->subdevices + 2 + - group)->private)->WRCapSel, mask); - - return 0; -} - -static int s626_dio_clear_irq(struct comedi_device *dev) -{ - unsigned int group; - - /* disable edge capture write command */ - DEBIwrite(dev, LP_MISC1, MISC1_NOEDCAP); + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - for (group = 0; group < S626_DIO_BANKS; group++) { - /* clear pending events and interrupt */ - DEBIwrite(dev, - ((struct dio_private *)(dev->subdevices + 2 + - group)->private)->WRCapSel, - 0xffff); - } + s626_debi_write(dev, S626_LP_WRDOUT(group), s->io_bits); - return 0; + return insn->n; } -/* Now this function initializes the value of the counter (data[0]) - and set the subdevice. To complete with trigger and interrupt - configuration */ +/* + * Now this function initializes the value of the counter (data[0]) + * and set the subdevice. To complete with trigger and interrupt + * configuration. + * + * FIXME: data[0] is supposed to be an INSN_CONFIG_xxx constant indicating + * what is being configured, but this function appears to be using data[0] + * as a variable. + */ static int s626_enc_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_COUNTER << BF_CLKSRC) | /* Operating mode is Counter. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - /* ( CNTDIR_UP << BF_CLKPOL ) | // Count direction is Down. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); - /* uint16_t DisableIntSrc=TRUE; */ - /* uint32_t Preloadvalue; //Counter initial value */ - uint16_t valueSrclatch = LATCHSRC_AB_READ; - uint16_t enab = CLKENAB_ALWAYS; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; - - DEBUG("s626_enc_insn_config: encoder config\n"); - - /* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ - - k->SetMode(dev, k, Setup, TRUE); - Preload(dev, k, *(insn->data)); - k->PulseIndex(dev, k); - SetLatchSource(dev, k, valueSrclatch); - k->SetEnable(dev, k, (uint16_t) (enab != 0)); + uint16_t setup = + /* Preload upon index. */ + S626_SET_STD_LOADSRC(S626_LOADSRC_INDX) | + /* Disable hardware index. */ + S626_SET_STD_INDXSRC(S626_INDXSRC_SOFT) | + /* Operating mode is Counter. */ + S626_SET_STD_ENCMODE(S626_ENCMODE_COUNTER) | + /* Active high clock. */ + S626_SET_STD_CLKPOL(S626_CLKPOL_POS) | + /* Clock multiplier is 1x. */ + S626_SET_STD_CLKMULT(S626_CLKMULT_1X) | + /* Enabled by index */ + S626_SET_STD_CLKENAB(S626_CLKENAB_INDEX); + /* uint16_t disable_int_src = true; */ + /* uint32_t Preloadvalue; //Counter initial value */ + uint16_t value_latchsrc = S626_LATCHSRC_AB_READ; + uint16_t enab = S626_CLKENAB_ALWAYS; + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; + + /* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ + + k->set_mode(dev, k, setup, true); + s626_preload(dev, k, data[0]); + k->pulse_index(dev, k); + s626_set_latch_source(dev, k, value_latchsrc); + k->set_enable(dev, k, (enab != 0)); return insn->n; } @@ -2382,17 +2551,12 @@ static int s626_enc_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; - - DEBUG("s626_enc_insn_read: encoder read channel %d\n", - CR_CHAN(insn->chanspec)); + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; for (n = 0; n < insn->n; n++) - data[n] = ReadLatch(dev, k); - - DEBUG("s626_enc_insn_read: encoder sample %d\n", data[n]); + data[n] = s626_read_latch(dev, k); return n; } @@ -2401,969 +2565,546 @@ static int s626_enc_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + const struct s626_enc_info *k = + &s626_enc_chan_info[CR_CHAN(insn->chanspec)]; - struct enc_private *k = &encpriv[CR_CHAN(insn->chanspec)]; - - DEBUG("s626_enc_insn_write: encoder write channel %d\n", - CR_CHAN(insn->chanspec)); - - /* Set the preload register */ - Preload(dev, k, data[0]); + /* Set the preload register */ + s626_preload(dev, k, data[0]); - /* Software index pulse forces the preload register to load */ - /* into the counter */ - k->SetLoadTrig(dev, k, 0); - k->PulseIndex(dev, k); - k->SetLoadTrig(dev, k, 2); - - DEBUG("s626_enc_insn_write: End encoder write\n"); + /* + * Software index pulse forces the preload register to load + * into the counter + */ + k->set_load_trig(dev, k, 0); + k->pulse_index(dev, k); + k->set_load_trig(dev, k, 2); return 1; } -static void s626_timer_load(struct comedi_device *dev, struct enc_private *k, - int tick) -{ - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_TIMER << BF_CLKSRC) | /* Operating mode is Timer. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - (CNTDIR_DOWN << BF_CLKPOL) | /* Count direction is Down. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); - uint16_t valueSrclatch = LATCHSRC_A_INDXA; - /* uint16_t enab=CLKENAB_ALWAYS; */ - - k->SetMode(dev, k, Setup, FALSE); - - /* Set the preload register */ - Preload(dev, k, tick); - - /* Software index pulse forces the preload register to load */ - /* into the counter */ - k->SetLoadTrig(dev, k, 0); - k->PulseIndex(dev, k); - - /* set reload on counter overflow */ - k->SetLoadTrig(dev, k, 1); - - /* set interrupt on overflow */ - k->SetIntSrc(dev, k, INTSRC_OVER); - - SetLatchSource(dev, k, valueSrclatch); - /* k->SetEnable(dev,k,(uint16_t)(enab != 0)); */ -} - -/* *********** DAC FUNCTIONS *********** */ - -/* Slot 0 base settings. */ -#define VECT0 (XSD2 | RSD3 | SIB_A2) -/* Slot 0 always shifts in 0xFF and store it to FB_BUFFER2. */ - -/* TrimDac LogicalChan-to-PhysicalChan mapping table. */ -static uint8_t trimchan[] = { 10, 9, 8, 3, 2, 7, 6, 1, 0, 5, 4 }; - -/* TrimDac LogicalChan-to-EepromAdrs mapping table. */ -static uint8_t trimadrs[] = { 0x40, 0x41, 0x42, 0x50, 0x51, 0x52, 0x53, 0x60, 0x61, 0x62, 0x63 }; - -static void LoadTrimDACs(struct comedi_device *dev) +static void s626_write_misc2(struct comedi_device *dev, uint16_t new_image) { - register uint8_t i; - - /* Copy TrimDac setpoint values from EEPROM to TrimDacs. */ - for (i = 0; i < ARRAY_SIZE(trimchan); i++) - WriteTrimDAC(dev, i, I2Cread(dev, trimadrs[i])); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_WENABLE); + s626_debi_write(dev, S626_LP_WRMISC2, new_image); + s626_debi_write(dev, S626_LP_MISC1, S626_MISC1_WDISABLE); } -static void WriteTrimDAC(struct comedi_device *dev, uint8_t LogicalChan, - uint8_t DacData) +static void s626_close_dma_b(struct comedi_device *dev, + struct s626_buffer_dma *pdma, size_t bsize) { - uint32_t chan; - - /* Save the new setpoint in case the application needs to read it back later. */ - devpriv->TrimSetpoint[LogicalChan] = (uint8_t) DacData; - - /* Map logical channel number to physical channel number. */ - chan = (uint32_t) trimchan[LogicalChan]; - - /* Set up TSL2 records for TrimDac write operation. All slots shift - * 0xFF in from pulled-up SD3 so that the end of the slot sequence - * can be detected. - */ - - SETVECT(2, XSD2 | XFIFO_1 | WS3); - /* Slot 2: Send high uint8_t to target TrimDac. */ - SETVECT(3, XSD2 | XFIFO_0 | WS3); - /* Slot 3: Send low uint8_t to target TrimDac. */ - SETVECT(4, XSD2 | XFIFO_3 | WS1); - /* Slot 4: Send NOP high uint8_t to DAC0 to keep clock running. */ - SETVECT(5, XSD2 | XFIFO_2 | WS1 | EOS); - /* Slot 5: Send NOP low uint8_t to DAC0. */ - - /* Construct and transmit target DAC's serial packet: - * ( 0000 AAAA ), ( DDDD DDDD ),( 0x00 ),( 0x00 ) where A<3:0> is the - * DAC channel's address, and D<7:0> is the DAC setpoint. Append a - * WORD value (that writes a channel 0 NOP command to a non-existent - * main DAC channel) that serves to keep the clock running after the - * packet has been sent to the target DAC. - */ - - /* Address the DAC channel within the trimdac device. */ - SendDAC(dev, ((uint32_t) chan << 8) - | (uint32_t) DacData); /* Include DAC setpoint data. */ -} - -/* ************** EEPROM ACCESS FUNCTIONS ************** */ -/* Read uint8_t from EEPROM. */ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + void *vbptr; + dma_addr_t vpptr; -static uint8_t I2Cread(struct comedi_device *dev, uint8_t addr) -{ - uint8_t rtnval; + if (pdma == NULL) + return; - /* Send EEPROM target address. */ - if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CW) - /* Byte2 = I2C command: write to I2C EEPROM device. */ - | I2C_B1(I2C_ATTRSTOP, addr) - /* Byte1 = EEPROM internal target address. */ - | I2C_B0(I2C_ATTRNOP, 0))) { /* Byte0 = Not sent. */ - /* Abort function and declare error if handshake failed. */ - DEBUG("I2Cread: error handshake I2Cread a\n"); - return 0; - } - /* Execute EEPROM read. */ - if (I2Chandshake(dev, I2C_B2(I2C_ATTRSTART, I2CR) - - /* Byte2 = I2C */ - /* command: read */ - /* from I2C EEPROM */ - /* device. */ - |I2C_B1(I2C_ATTRSTOP, 0) - - /* Byte1 receives */ - /* uint8_t from */ - /* EEPROM. */ - |I2C_B0(I2C_ATTRNOP, 0))) { /* Byte0 = Not sent. */ - - /* Abort function and declare error if handshake failed. */ - DEBUG("I2Cread: error handshake I2Cread b\n"); - return 0; + /* 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; } - /* Return copy of EEPROM value. */ - rtnval = (uint8_t) (RR7146(P_I2CCTRL) >> 16); - return rtnval; } -static uint32_t I2Chandshake(struct comedi_device *dev, uint32_t val) +static void s626_counters_init(struct comedi_device *dev) { - /* Write I2C command to I2C Transfer Control shadow register. */ - WR7146(P_I2CCTRL, val); - - /* Upload I2C shadow registers into working registers and wait for */ - /* upload confirmation. */ - - MC_ENABLE(P_MC2, MC2_UPLD_IIC); - while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) - ; - - /* Wait until I2C bus transfer is finished or an error occurs. */ - while ((RR7146(P_I2CCTRL) & (I2C_BUSY | I2C_ERR)) == I2C_BUSY) - ; - - /* Return non-zero if I2C error occurred. */ - return RR7146(P_I2CCTRL) & I2C_ERR; + int chan; + const struct s626_enc_info *k; + uint16_t setup = + /* Preload upon index. */ + S626_SET_STD_LOADSRC(S626_LOADSRC_INDX) | + /* Disable hardware index. */ + S626_SET_STD_INDXSRC(S626_INDXSRC_SOFT) | + /* Operating mode is counter. */ + S626_SET_STD_ENCMODE(S626_ENCMODE_COUNTER) | + /* Active high clock. */ + S626_SET_STD_CLKPOL(S626_CLKPOL_POS) | + /* Clock multiplier is 1x. */ + S626_SET_STD_CLKMULT(S626_CLKMULT_1X) | + /* Enabled by index */ + S626_SET_STD_CLKENAB(S626_CLKENAB_INDEX); + /* + * Disable all counter interrupts and clear any captured counter events. + */ + for (chan = 0; chan < S626_ENCODER_CHANNELS; chan++) { + k = &s626_enc_chan_info[chan]; + k->set_mode(dev, k, setup, true); + k->set_int_src(dev, k, 0); + k->reset_cap_flags(dev, k); + k->set_enable(dev, k, S626_CLKENAB_ALWAYS); + } } -/* Private helper function: Write setpoint to an application DAC channel. */ - -static void SetDAC(struct comedi_device *dev, uint16_t chan, short dacdata) +static int s626_allocate_dma_buffers(struct comedi_device *dev) { - register uint16_t signmask; - register uint32_t WSImage; - - /* Adjust DAC data polarity and set up Polarity Control Register */ - /* image. */ - signmask = 1 << chan; - if (dacdata < 0) { - dacdata = -dacdata; - devpriv->Dacpol |= signmask; - } else - devpriv->Dacpol &= ~signmask; - - /* Limit DAC setpoint value to valid range. */ - if ((uint16_t) dacdata > 0x1FFF) - dacdata = 0x1FFF; - - /* Set up TSL2 records (aka "vectors") for DAC update. Vectors V2 - * and V3 transmit the setpoint to the target DAC. V4 and V5 send - * data to a non-existent TrimDac channel just to keep the clock - * running after sending data to the target DAC. This is necessary - * to eliminate the clock glitch that would otherwise occur at the - * end of the target DAC's serial data stream. When the sequence - * restarts at V0 (after executing V5), the gate array automatically - * disables gating for the DAC clock and all DAC chip selects. - */ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct s626_private *devpriv = dev->private; + void *addr; + dma_addr_t appdma; - WSImage = (chan & 2) ? WS1 : WS2; - /* Choose DAC chip select to be asserted. */ - SETVECT(2, XSD2 | XFIFO_1 | WSImage); - /* Slot 2: Transmit high data byte to target DAC. */ - SETVECT(3, XSD2 | XFIFO_0 | WSImage); - /* Slot 3: Transmit low data byte to target DAC. */ - SETVECT(4, XSD2 | XFIFO_3 | WS3); - /* Slot 4: Transmit to non-existent TrimDac channel to keep clock */ - SETVECT(5, XSD2 | XFIFO_2 | WS3 | EOS); - /* Slot 5: running after writing target DAC's low data byte. */ + addr = pci_alloc_consistent(pcidev, S626_DMABUF_SIZE, &appdma); + if (!addr) + return -ENOMEM; + devpriv->ana_buf.logical_base = addr; + devpriv->ana_buf.physical_base = appdma; - /* Construct and transmit target DAC's serial packet: - * ( A10D DDDD ),( DDDD DDDD ),( 0x0F ),( 0x00 ) where A is chan<0>, - * and D<12:0> is the DAC setpoint. Append a WORD value (that writes - * to a non-existent TrimDac channel) that serves to keep the clock - * running after the packet has been sent to the target DAC. - */ - SendDAC(dev, 0x0F000000 - /* Continue clock after target DAC data (write to non-existent trimdac). */ - | 0x00004000 - /* Address the two main dual-DAC devices (TSL's chip select enables - * target device). */ - | ((uint32_t) (chan & 1) << 15) - /* Address the DAC channel within the device. */ - | (uint32_t) dacdata); /* Include DAC setpoint data. */ + addr = pci_alloc_consistent(pcidev, S626_DMABUF_SIZE, &appdma); + if (!addr) + return -ENOMEM; + devpriv->rps_buf.logical_base = addr; + devpriv->rps_buf.physical_base = appdma; + return 0; } -/* Private helper function: Transmit serial data to DAC via Audio - * channel 2. Assumes: (1) TSL2 slot records initialized, and (2) - * Dacpol contains valid target image. - */ - -static void SendDAC(struct comedi_device *dev, uint32_t val) +static int s626_initialize(struct comedi_device *dev) { + struct s626_private *devpriv = dev->private; + dma_addr_t phys_buf; + uint16_t chan; + int i; + int ret; - /* START THE SERIAL CLOCK RUNNING ------------- */ + /* Enable DEBI and audio pins, enable I2C interface */ + s626_mc_enable(dev, S626_MC1_DEBI | S626_MC1_AUDIO | S626_MC1_I2C, + S626_P_MC1); - /* Assert DAC polarity control and enable gating of DAC serial clock - * and audio bit stream signals. At this point in time we must be - * assured of being in time slot 0. If we are not in slot 0, the - * serial clock and audio stream signals will be disabled; this is - * because the following DEBIwrite statement (which enables signals - * to be passed through the gate array) would execute before the - * trailing edge of WS1/WS3 (which turns off the signals), thus - * causing the signals to be inactive during the DAC write. + /* + * Configure DEBI operating mode + * + * Local bus is 16 bits wide + * Declare DEBI transfer timeout interval + * Set up byte lane steering + * Intel-compatible local bus (DEBI never times out) */ - DEBIwrite(dev, LP_DACPOL, devpriv->Dacpol); + writel(S626_DEBI_CFG_SLAVE16 | + (S626_DEBI_TOUT << S626_DEBI_CFG_TOUT_BIT) | S626_DEBI_SWAP | + S626_DEBI_CFG_INTEL, devpriv->mmio + S626_P_DEBICFG); - /* TRANSFER OUTPUT DWORD VALUE INTO A2'S OUTPUT FIFO ---------------- */ + /* Disable MMU paging */ + writel(S626_DEBI_PAGE_DISABLE, devpriv->mmio + S626_P_DEBIPAGE); - /* Copy DAC setpoint value to DAC's output DMA buffer. */ + /* Init GPIO so that ADC Start* is negated */ + writel(S626_GPIO_BASE | S626_GPIO1_HI, devpriv->mmio + S626_P_GPIO); - /* WR7146( (uint32_t)devpriv->pDacWBuf, val ); */ - *devpriv->pDacWBuf = val; + /* I2C device address for onboard eeprom (revb) */ + devpriv->i2c_adrs = 0xA0; - /* enab the output DMA transfer. This will cause the DMAC to copy - * the DAC's data value to A2's output FIFO. The DMA transfer will - * then immediately terminate because the protection address is - * reached upon transfer of the first DWORD value. + /* + * Issue an I2C ABORT command to halt any I2C + * operation in progress and reset BUSY flag. */ - MC_ENABLE(P_MC1, MC1_A2OUT); - - /* While the DMA transfer is executing ... */ + writel(S626_I2C_CLKSEL | S626_I2C_ABORT, + devpriv->mmio + S626_P_I2CSTAT); + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; - /* Reset Audio2 output FIFO's underflow flag (along with any other - * FIFO underflow/overflow flags). When set, this flag will - * indicate that we have emerged from slot 0. + /* + * Per SAA7146 data sheet, write to STATUS + * reg twice to reset all I2C error flags. */ - WR7146(P_ISR, ISR_AFOU); + for (i = 0; i < 2; i++) { + writel(S626_I2C_CLKSEL, devpriv->mmio + S626_P_I2CSTAT); + s626_mc_enable(dev, S626_MC2_UPLD_IIC, S626_P_MC2); + ret = comedi_timeout(dev, NULL, NULL, s626_i2c_handshake_eoc, 0); + if (ret) + return ret; + } - /* Wait for the DMA transfer to finish so that there will be data - * available in the FIFO when time slot 1 tries to transfer a DWORD - * from the FIFO to the output buffer register. We test for DMA - * Done by polling the DMAC enable flag; this flag is automatically - * cleared when the transfer has finished. + /* + * Init audio interface functional attributes: set DAC/ADC + * serial clock rates, invert DAC serial clock so that + * DAC data setup times are satisfied, enable DAC serial + * clock out. */ - while ((RR7146(P_MC1) & MC1_A2OUT) != 0) - ; - - /* START THE OUTPUT STREAM TO THE TARGET DAC -------------------- */ + writel(S626_ACON2_INIT, devpriv->mmio + S626_P_ACON2); - /* FIFO data is now available, so we enable execution of time slots - * 1 and higher by clearing the EOS flag in slot 0. Note that SD3 - * will be shifted in and stored in FB_BUFFER2 for end-of-slot-list - * detection. + /* + * Set up TSL1 slot list, which is used to control the + * accumulation of ADC data: S626_RSD1 = shift data in on SD1. + * S626_SIB_A1 = store data uint8_t at next available location + * in FB BUFFER1 register. */ - SETVECT(0, XSD2 | RSD3 | SIB_A2); + writel(S626_RSD1 | S626_SIB_A1, devpriv->mmio + S626_P_TSL1); + writel(S626_RSD1 | S626_SIB_A1 | S626_EOS, + devpriv->mmio + S626_P_TSL1 + 4); - /* Wait for slot 1 to execute to ensure that the Packet will be - * transmitted. This is detected by polling the Audio2 output FIFO - * underflow flag, which will be set when slot 1 execution has - * finished transferring the DAC's data DWORD from the output FIFO - * to the output buffer register. - */ - while ((RR7146(P_SSR) & SSR_AF2_OUT) == 0) - ; + /* Enable TSL1 slot list so that it executes all the time */ + writel(S626_ACON1_ADCSTART, devpriv->mmio + S626_P_ACON1); - /* Set up to trap execution at slot 0 when the TSL sequencer cycles - * back to slot 0 after executing the EOS in slot 5. Also, - * simultaneously shift out and in the 0x00 that is ALWAYS the value - * stored in the last byte to be shifted out of the FIFO's DWORD - * buffer register. + /* + * Initialize RPS registers used for ADC */ - SETVECT(0, XSD2 | XFIFO_2 | RSD2 | SIB_A2 | EOS); - /* WAIT FOR THE TRANSACTION TO FINISH ----------------------- */ + /* Physical start of RPS program */ + writel((uint32_t)devpriv->rps_buf.physical_base, + devpriv->mmio + S626_P_RPSADDR1); + /* RPS program performs no explicit mem writes */ + writel(0, devpriv->mmio + S626_P_RPSPAGE1); + /* Disable RPS timeouts */ + writel(0, devpriv->mmio + S626_P_RPS1_TOUT); - /* Wait for the TSL to finish executing all time slots before - * exiting this function. We must do this so that the next DAC - * write doesn't start, thereby enabling clock/chip select signals: - * - * 1. Before the TSL sequence cycles back to slot 0, which disables - * the clock/cs signal gating and traps slot // list execution. - * we have not yet finished slot 5 then the clock/cs signals are - * still gated and we have not finished transmitting the stream. +#if 0 + /* + * SAA7146 BUG WORKAROUND * - * 2. While slots 2-5 are executing due to a late slot 0 trap. In - * this case, the slot sequence is currently repeating, but with - * clock/cs signals disabled. We must wait for slot 0 to trap - * execution before setting up the next DAC setpoint DMA transfer - * and enabling the clock/cs signals. To detect the end of slot 5, - * we test for the FB_BUFFER2 MSB contents to be equal to 0xFF. If - * the TSL has not yet finished executing slot 5 ... + * Initialize SAA7146 ADC interface to a known state by + * invoking ADCs until FB BUFFER 1 register shows that it + * is correctly receiving ADC data. This is necessary + * because the SAA7146 ADC interface does not start up in + * a defined state after a PCI reset. */ - if ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) { - /* The trap was set on time and we are still executing somewhere - * in slots 2-5, so we now wait for slot 0 to execute and trap - * TSL execution. This is detected when FB_BUFFER2 MSB changes - * from 0xFF to 0x00, which slot 0 causes to happen by shifting - * out/in on SD2 the 0x00 that is always referenced by slot 5. + { + struct comedi_subdevice *s = dev->read_subdev; + uint8_t poll_list; + uint16_t adc_data; + uint16_t start_val; + uint16_t index; + unsigned int data[16]; + + /* Create a simple polling list for analog input channel 0 */ + poll_list = S626_EOPL; + s626_reset_adc(dev, &poll_list); + + /* Get initial ADC value */ + s626_ai_rinsn(dev, s, NULL, data); + start_val = data[0]; + + /* + * VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED + * EXECUTION. + * + * Invoke ADCs until the new ADC value differs from the initial + * value or a timeout occurs. The timeout protects against the + * possibility that the driver is restarting and the ADC data is + * a fixed value resulting from the applied ADC analog input + * being unusually quiet or at the rail. */ - while ((RR7146(P_FB_BUFFER2) & 0xFF000000) != 0) - ; + for (index = 0; index < 500; index++) { + s626_ai_rinsn(dev, s, NULL, data); + adc_data = data[0]; + if (adc_data != start_val) + break; + } } - /* Either (1) we were too late setting the slot 0 trap; the TSL - * sequencer restarted slot 0 before we could set the EOS trap flag, - * or (2) we were not late and execution is now trapped at slot 0. - * In either case, we must now change slot 0 so that it will store - * value 0xFF (instead of 0x00) to FB_BUFFER2 next time it executes. - * In order to do this, we reprogram slot 0 so that it will shift in - * SD3, which is driven only by a pull-up resistor. - */ - SETVECT(0, RSD3 | SIB_A2 | EOS); +#endif /* SAA7146 BUG WORKAROUND */ - /* Wait for slot 0 to execute, at which time the TSL is setup for - * the next DAC write. This is detected when FB_BUFFER2 MSB changes - * from 0x00 to 0xFF. + /* + * Initialize the DAC interface */ - while ((RR7146(P_FB_BUFFER2) & 0xFF000000) == 0) - ; -} - -static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage) -{ - DEBIwrite(dev, LP_MISC1, MISC1_WENABLE); /* enab writes to */ - /* MISC2 register. */ - DEBIwrite(dev, LP_WRMISC2, NewImage); /* Write new image to MISC2. */ - DEBIwrite(dev, LP_MISC1, MISC1_WDISABLE); /* Disable writes to MISC2. */ -} - -/* Initialize the DEBI interface for all transfers. */ - -static uint16_t DEBIread(struct comedi_device *dev, uint16_t addr) -{ - uint16_t retval; - - /* Set up DEBI control register value in shadow RAM. */ - WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr); - - /* Execute the DEBI transfer. */ - DEBItransfer(dev); - - /* Fetch target register value. */ - retval = (uint16_t) RR7146(P_DEBIAD); - /* Return register value. */ - return retval; -} - -/* Execute a DEBI transfer. This must be called from within a */ -/* critical section. */ -static void DEBItransfer(struct comedi_device *dev) -{ - /* Initiate upload of shadow RAM to DEBI control register. */ - MC_ENABLE(P_MC2, MC2_UPLD_DEBI); - - /* Wait for completion of upload from shadow RAM to DEBI control */ - /* register. */ - while (!MC_TEST(P_MC2, MC2_UPLD_DEBI)) - ; - - /* Wait until DEBI transfer is done. */ - while (RR7146(P_PSR) & PSR_DEBI_S) - ; -} + /* + * Init Audio2's output DMAC attributes: + * burst length = 1 DWORD + * threshold = 1 DWORD. + */ + writel(0, devpriv->mmio + S626_P_PCI_BT_A); -/* Write a value to a gate array register. */ -static void DEBIwrite(struct comedi_device *dev, uint16_t addr, uint16_t wdata) -{ + /* + * Init Audio2's output DMA physical addresses. The protection + * address is set to 1 DWORD past the base address so that a + * single DWORD will be transferred each time a DMA transfer is + * enabled. + */ + phys_buf = devpriv->ana_buf.physical_base + + (S626_DAC_WDMABUF_OS * sizeof(uint32_t)); + writel((uint32_t)phys_buf, devpriv->mmio + S626_P_BASEA2_OUT); + writel((uint32_t)(phys_buf + sizeof(uint32_t)), + devpriv->mmio + S626_P_PROTA2_OUT); - /* Set up DEBI control register value in shadow RAM. */ - WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr); - WR7146(P_DEBIAD, wdata); + /* + * Cache Audio2's output DMA buffer logical address. This is + * where DAC data is buffered for A2 output DMA transfers. + */ + devpriv->dac_wbuf = (uint32_t *)devpriv->ana_buf.logical_base + + S626_DAC_WDMABUF_OS; - /* Execute the DEBI transfer. */ - DEBItransfer(dev); -} + /* + * Audio2's output channels does not use paging. The + * protection violation handling bit is set so that the + * DMAC will automatically halt and its PCI address pointer + * will be reset when the protection address is reached. + */ + writel(8, devpriv->mmio + S626_P_PAGEA2_OUT); -/* Replace the specified bits in a gate array register. Imports: mask - * specifies bits that are to be preserved, wdata is new value to be - * or'd with the masked original. - */ -static void DEBIreplace(struct comedi_device *dev, uint16_t addr, uint16_t mask, - uint16_t wdata) -{ + /* + * Initialize time slot list 2 (TSL2), which is used to control + * the clock generation for and serialization of data to be sent + * to the DAC devices. Slot 0 is a NOP that is used to trap TSL + * execution; this permits other slots to be safely modified + * without first turning off the TSL sequencer (which is + * apparently impossible to do). Also, SD3 (which is driven by a + * pull-up resistor) is shifted in and stored to the MSB of + * FB_BUFFER2 to be used as evidence that the slot sequence has + * not yet finished executing. + */ - /* Copy target gate array register into P_DEBIAD register. */ - WR7146(P_DEBICMD, DEBI_CMD_RDWORD | addr); - /* Set up DEBI control reg value in shadow RAM. */ - DEBItransfer(dev); /* Execute the DEBI Read transfer. */ + /* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2 */ + writel(S626_XSD2 | S626_RSD3 | S626_SIB_A2 | S626_EOS, + devpriv->mmio + S626_VECTPORT(0)); - /* Write back the modified image. */ - WR7146(P_DEBICMD, DEBI_CMD_WRWORD | addr); - /* Set up DEBI control reg value in shadow RAM. */ + /* + * Initialize slot 1, which is constant. Slot 1 causes a + * DWORD to be transferred from audio channel 2's output FIFO + * to the FIFO's output buffer so that it can be serialized + * and sent to the DAC during subsequent slots. All remaining + * slots are dynamically populated as required by the target + * DAC device. + */ - WR7146(P_DEBIAD, wdata | ((uint16_t) RR7146(P_DEBIAD) & mask)); - /* Modify the register image. */ - DEBItransfer(dev); /* Execute the DEBI Write transfer. */ -} + /* Slot 1: Fetch DWORD from Audio2's output FIFO */ + writel(S626_LF_A2, devpriv->mmio + S626_VECTPORT(1)); -static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma, - size_t bsize) -{ - void *vbptr; - dma_addr_t vpptr; + /* Start DAC's audio interface (TSL2) running */ + writel(S626_ACON1_DACSTART, devpriv->mmio + S626_P_ACON1); - DEBUG("CloseDMAB: Entering S626DRV_CloseDMAB():\n"); - if (pdma == NULL) - return; - /* find the matching allocation from the board struct */ + /* + * Init Trim DACs to calibrated values. Do it twice because the + * SAA7146 audio channel does not always reset properly and + * sometimes causes the first few TrimDAC writes to malfunction. + */ + s626_load_trim_dacs(dev); + ret = s626_load_trim_dacs(dev); + if (ret) + return ret; - vbptr = pdma->LogicalBase; - vpptr = pdma->PhysicalBase; - if (vbptr) { - pci_free_consistent(devpriv->pdev, bsize, vbptr, vpptr); - pdma->LogicalBase = 0; - pdma->PhysicalBase = 0; + /* + * Manually init all gate array hardware in case this is a soft + * reset (we have no way of determining whether this is a warm + * or cold start). This is necessary because the gate array will + * reset only in response to a PCI hard reset; there is no soft + * reset function. + */ - DEBUG("CloseDMAB(): Logical=%p, bsize=%d, Physical=0x%x\n", - vbptr, bsize, (uint32_t) vpptr); + /* + * Init all DAC outputs to 0V and init all DAC setpoint and + * polarity images. + */ + for (chan = 0; chan < S626_DAC_CHANNELS; chan++) { + ret = s626_set_dac(dev, chan, 0); + if (ret) + return ret; } -} - -/* ****** COUNTER FUNCTIONS ******* */ -/* All counter functions address a specific counter by means of the - * "Counter" argument, which is a logical counter number. The Counter - * argument may have any of the following legal values: 0=0A, 1=1A, - * 2=2A, 3=0B, 4=1B, 5=2B. - */ -/* Forward declarations for functions that are common to both A and B counters: */ + /* Init counters */ + s626_counters_init(dev); -/* ****** PRIVATE COUNTER FUNCTIONS ****** */ - -/* Read a counter's output latch. */ - -static uint32_t ReadLatch(struct comedi_device *dev, struct enc_private *k) -{ - register uint32_t value; - /* DEBUG FIXME DEBUG("ReadLatch: Read Latch enter\n"); */ - - /* Latch counts and fetch LSW of latched counts value. */ - value = (uint32_t) DEBIread(dev, k->MyLatchLsw); - - /* Fetch MSW of latched counts and combine with LSW. */ - value |= ((uint32_t) DEBIread(dev, k->MyLatchLsw + 2) << 16); - - /* DEBUG FIXME DEBUG("ReadLatch: Read Latch exit\n"); */ - - /* Return latched counts. */ - return value; -} - -/* Reset a counter's index and overflow event capture flags. */ - -static void ResetCapFlags_A(struct comedi_device *dev, struct enc_private *k) -{ - DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL), - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A); -} - -static void ResetCapFlags_B(struct comedi_device *dev, struct enc_private *k) -{ - DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL), - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B); -} - -/* Return counter setup in a format (COUNTER_SETUP) that is consistent */ -/* for both A and B counters. */ - -static uint16_t GetMode_A(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t cra; - register uint16_t crb; - register uint16_t setup; - - /* Fetch CRA and CRB register images. */ - cra = DEBIread(dev, k->MyCRA); - crb = DEBIread(dev, k->MyCRB); - - /* Populate the standardized counter setup bit fields. Note: */ - /* IndexSrc is restricted to ENC_X or IndxPol. */ - setup = ((cra & STDMSK_LOADSRC) /* LoadSrc = LoadSrcA. */ - |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC) /* LatchSrc = LatchSrcA. */ - |((cra << (STDBIT_INTSRC - CRABIT_INTSRC_A)) & STDMSK_INTSRC) /* IntSrc = IntSrcA. */ - |((cra << (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1))) & STDMSK_INDXSRC) /* IndxSrc = IndxSrcA<1>. */ - |((cra >> (CRABIT_INDXPOL_A - STDBIT_INDXPOL)) & STDMSK_INDXPOL) /* IndxPol = IndxPolA. */ - |((crb >> (CRBBIT_CLKENAB_A - STDBIT_CLKENAB)) & STDMSK_CLKENAB)); /* ClkEnab = ClkEnabA. */ - - /* Adjust mode-dependent parameters. */ - if (cra & (2 << CRABIT_CLKSRC_A)) /* If Timer mode (ClkSrcA<1> == 1): */ - setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |((cra << (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) & STDMSK_CLKPOL) /* Set ClkPol to indicate count direction (ClkSrcA<0>). */ - |(MULT_X1 << STDBIT_CLKMULT)); /* ClkMult must be 1x in Timer mode. */ + /* + * Without modifying the state of the Battery Backup enab, disable + * the watchdog timer, set DIO channels 0-5 to operate in the + * standard DIO (vs. counter overflow) mode, disable the battery + * charger, and reset the watchdog interval selector to zero. + */ + s626_write_misc2(dev, (s626_debi_read(dev, S626_LP_RDMISC2) & + S626_MISC2_BATT_ENABLE)); - else /* If Counter mode (ClkSrcA<1> == 0): */ - setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC) /* Indicate Counter mode. */ - |((cra >> (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) & STDMSK_CLKPOL) /* Pass through ClkPol. */ - |(((cra & CRAMSK_CLKMULT_A) == (MULT_X0 << CRABIT_CLKMULT_A)) ? /* Force ClkMult to 1x if not legal, else pass through. */ - (MULT_X1 << STDBIT_CLKMULT) : - ((cra >> (CRABIT_CLKMULT_A - - STDBIT_CLKMULT)) & STDMSK_CLKMULT))); + /* Initialize the digital I/O subsystem */ + s626_dio_init(dev); - /* Return adjusted counter setup. */ - return setup; + return 0; } -static uint16_t GetMode_B(struct comedi_device *dev, struct enc_private *k) +static int s626_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - register uint16_t cra; - register uint16_t crb; - register uint16_t setup; - - /* Fetch CRA and CRB register images. */ - cra = DEBIread(dev, k->MyCRA); - crb = DEBIread(dev, k->MyCRB); - - /* Populate the standardized counter setup bit fields. Note: */ - /* IndexSrc is restricted to ENC_X or IndxPol. */ - setup = (((crb << (STDBIT_INTSRC - CRBBIT_INTSRC_B)) & STDMSK_INTSRC) /* IntSrc = IntSrcB. */ - |((crb << (STDBIT_LATCHSRC - CRBBIT_LATCHSRC)) & STDMSK_LATCHSRC) /* LatchSrc = LatchSrcB. */ - |((crb << (STDBIT_LOADSRC - CRBBIT_LOADSRC_B)) & STDMSK_LOADSRC) /* LoadSrc = LoadSrcB. */ - |((crb << (STDBIT_INDXPOL - CRBBIT_INDXPOL_B)) & STDMSK_INDXPOL) /* IndxPol = IndxPolB. */ - |((crb >> (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) & STDMSK_CLKENAB) /* ClkEnab = ClkEnabB. */ - |((cra >> ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)) & STDMSK_INDXSRC)); /* IndxSrc = IndxSrcB<1>. */ - - /* Adjust mode-dependent parameters. */ - if ((crb & CRBMSK_CLKMULT_B) == (MULT_X0 << CRBBIT_CLKMULT_B)) /* If Extender mode (ClkMultB == MULT_X0): */ - setup |= ((CLKSRC_EXTENDER << STDBIT_CLKSRC) /* Indicate Extender mode. */ - |(MULT_X1 << STDBIT_CLKMULT) /* Indicate multiplier is 1x. */ - |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL)); /* Set ClkPol equal to Timer count direction (ClkSrcB<0>). */ - - else if (cra & (2 << CRABIT_CLKSRC_B)) /* If Timer mode (ClkSrcB<1> == 1): */ - setup |= ((CLKSRC_TIMER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |(MULT_X1 << STDBIT_CLKMULT) /* Indicate multiplier is 1x. */ - |((cra >> (CRABIT_CLKSRC_B - STDBIT_CLKPOL)) & STDMSK_CLKPOL)); /* Set ClkPol equal to Timer count direction (ClkSrcB<0>). */ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct s626_private *devpriv; + struct comedi_subdevice *s; + int ret; - else /* If Counter mode (ClkSrcB<1> == 0): */ - setup |= ((CLKSRC_COUNTER << STDBIT_CLKSRC) /* Indicate Timer mode. */ - |((crb >> (CRBBIT_CLKMULT_B - STDBIT_CLKMULT)) & STDMSK_CLKMULT) /* Clock multiplier is passed through. */ - |((crb << (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) & STDMSK_CLKPOL)); /* Clock polarity is passed through. */ + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - /* Return adjusted counter setup. */ - return setup; -} + ret = comedi_pci_enable(dev); + if (ret) + return ret; -/* - * Set the operating mode for the specified counter. The setup - * parameter is treated as a COUNTER_SETUP data type. The following - * parameters are programmable (all other parms are ignored): ClkMult, - * ClkPol, ClkEnab, IndexSrc, IndexPol, LoadSrc. - */ - -static void SetMode_A(struct comedi_device *dev, struct enc_private *k, - uint16_t Setup, uint16_t DisableIntSrc) -{ - register uint16_t cra; - register uint16_t crb; - register uint16_t setup = Setup; /* Cache the Standard Setup. */ + devpriv->mmio = pci_ioremap_bar(pcidev, 0); + if (!devpriv->mmio) + return -ENOMEM; - /* Initialize CRA and CRB images. */ - cra = ((setup & CRAMSK_LOADSRC_A) /* Preload trigger is passed through. */ - |((setup & STDMSK_INDXSRC) >> (STDBIT_INDXSRC - (CRABIT_INDXSRC_A + 1)))); /* IndexSrc is restricted to ENC_X or IndxPol. */ + /* disable master interrupt */ + writel(0, devpriv->mmio + S626_P_IER); - crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A /* Reset any pending CounterA event captures. */ - | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_A - STDBIT_CLKENAB))); /* Clock enable is passed through. */ + /* soft reset */ + writel(S626_MC1_SOFT_RESET, devpriv->mmio + S626_P_MC1); - /* Force IntSrc to Disabled if DisableIntSrc is asserted. */ - if (!DisableIntSrc) - cra |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC - - CRABIT_INTSRC_A)); + /* DMA FIXME DMA// */ - /* Populate all mode-dependent attributes of CRA & CRB images. */ - switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) { - case CLKSRC_EXTENDER: /* Extender Mode: Force to Timer mode */ - /* (Extender valid only for B counters). */ + ret = s626_allocate_dma_buffers(dev); + if (ret) + return ret; - case CLKSRC_TIMER: /* Timer Mode: */ - cra |= ((2 << CRABIT_CLKSRC_A) /* ClkSrcA<1> selects system clock */ - |((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRABIT_CLKSRC_A)) /* with count direction (ClkSrcA<0>) obtained from ClkPol. */ - |(1 << CRABIT_CLKPOL_A) /* ClkPolA behaves as always-on clock enable. */ - |(MULT_X1 << CRABIT_CLKMULT_A)); /* ClkMult must be 1x. */ - break; + if (pcidev->irq) { + ret = request_irq(pcidev->irq, s626_irq_handler, IRQF_SHARED, + dev->board_name, dev); - default: /* Counter Mode: */ - cra |= (CLKSRC_COUNTER /* Select ENC_C and ENC_D as clock/direction inputs. */ - | ((setup & STDMSK_CLKPOL) << (CRABIT_CLKPOL_A - STDBIT_CLKPOL)) /* Clock polarity is passed through. */ - |(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ? /* Force multiplier to x1 if not legal, otherwise pass through. */ - (MULT_X1 << CRABIT_CLKMULT_A) : - ((setup & STDMSK_CLKMULT) << (CRABIT_CLKMULT_A - - STDBIT_CLKMULT)))); + if (ret == 0) + dev->irq = pcidev->irq; } - /* Force positive index polarity if IndxSrc is software-driven only, */ - /* otherwise pass it through. */ - if (~setup & STDMSK_INDXSRC) - cra |= ((setup & STDMSK_INDXPOL) << (CRABIT_INDXPOL_A - - STDBIT_INDXPOL)); - - /* If IntSrc has been forced to Disabled, update the MISC2 interrupt */ - /* enable mask to indicate the counter interrupt is disabled. */ - if (DisableIntSrc) - devpriv->CounterIntEnabs &= ~k->MyEventBits[3]; - - /* While retaining CounterB and LatchSrc configurations, program the */ - /* new counter operating mode. */ - DEBIreplace(dev, k->MyCRA, CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B, cra); - DEBIreplace(dev, k->MyCRB, - (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)), crb); -} - -static void SetMode_B(struct comedi_device *dev, struct enc_private *k, - uint16_t Setup, uint16_t DisableIntSrc) -{ - register uint16_t cra; - register uint16_t crb; - register uint16_t setup = Setup; /* Cache the Standard Setup. */ - - /* Initialize CRA and CRB images. */ - cra = ((setup & STDMSK_INDXSRC) << ((CRABIT_INDXSRC_B + 1) - STDBIT_INDXSRC)); /* IndexSrc field is restricted to ENC_X or IndxPol. */ - - crb = (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B /* Reset event captures and disable interrupts. */ - | ((setup & STDMSK_CLKENAB) << (CRBBIT_CLKENAB_B - STDBIT_CLKENAB)) /* Clock enable is passed through. */ - |((setup & STDMSK_LOADSRC) >> (STDBIT_LOADSRC - CRBBIT_LOADSRC_B))); /* Preload trigger source is passed through. */ - - /* Force IntSrc to Disabled if DisableIntSrc is asserted. */ - if (!DisableIntSrc) - crb |= ((setup & STDMSK_INTSRC) >> (STDBIT_INTSRC - - CRBBIT_INTSRC_B)); - - /* Populate all mode-dependent attributes of CRA & CRB images. */ - switch ((setup & STDMSK_CLKSRC) >> STDBIT_CLKSRC) { - case CLKSRC_TIMER: /* Timer Mode: */ - cra |= ((2 << CRABIT_CLKSRC_B) /* ClkSrcB<1> selects system clock */ - |((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL))); /* with direction (ClkSrcB<0>) obtained from ClkPol. */ - crb |= ((1 << CRBBIT_CLKPOL_B) /* ClkPolB behaves as always-on clock enable. */ - |(MULT_X1 << CRBBIT_CLKMULT_B)); /* ClkMultB must be 1x. */ - break; - - case CLKSRC_EXTENDER: /* Extender Mode: */ - cra |= ((2 << CRABIT_CLKSRC_B) /* ClkSrcB source is OverflowA (same as "timer") */ - |((setup & STDMSK_CLKPOL) << (CRABIT_CLKSRC_B - STDBIT_CLKPOL))); /* with direction obtained from ClkPol. */ - crb |= ((1 << CRBBIT_CLKPOL_B) /* ClkPolB controls IndexB -- always set to active. */ - |(MULT_X0 << CRBBIT_CLKMULT_B)); /* ClkMultB selects OverflowA as the clock source. */ - break; + ret = comedi_alloc_subdevices(dev, 6); + if (ret) + return ret; - default: /* Counter Mode: */ - cra |= (CLKSRC_COUNTER << CRABIT_CLKSRC_B); /* Select ENC_C and ENC_D as clock/direction inputs. */ - crb |= (((setup & STDMSK_CLKPOL) >> (STDBIT_CLKPOL - CRBBIT_CLKPOL_B)) /* ClkPol is passed through. */ - |(((setup & STDMSK_CLKMULT) == (MULT_X0 << STDBIT_CLKMULT)) ? /* Force ClkMult to x1 if not legal, otherwise pass through. */ - (MULT_X1 << CRBBIT_CLKMULT_B) : - ((setup & STDMSK_CLKMULT) << (CRBBIT_CLKMULT_B - - STDBIT_CLKMULT)))); + s = &dev->subdevices[0]; + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_DIFF; + s->n_chan = S626_ADC_CHANNELS; + s->maxdata = 0x3fff; + s->range_table = &s626_range_table; + s->len_chanlist = S626_ADC_CHANNELS; + s->insn_read = s626_ai_insn_read; + if (dev->irq) { + dev->read_subdev = s; + s->subdev_flags |= SDF_CMD_READ; + s->do_cmd = s626_ai_cmd; + s->do_cmdtest = s626_ai_cmdtest; + s->cancel = s626_ai_cancel; } - /* Force positive index polarity if IndxSrc is software-driven only, */ - /* otherwise pass it through. */ - if (~setup & STDMSK_INDXSRC) - crb |= ((setup & STDMSK_INDXPOL) >> (STDBIT_INDXPOL - - CRBBIT_INDXPOL_B)); - - /* If IntSrc has been forced to Disabled, update the MISC2 interrupt */ - /* enable mask to indicate the counter interrupt is disabled. */ - if (DisableIntSrc) - devpriv->CounterIntEnabs &= ~k->MyEventBits[3]; + s = &dev->subdevices[1]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + 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 = &dev->subdevices[2]; + /* digital I/O subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->io_bits = 0xffff; + s->private = (void *)0; /* DIO group 0 */ + s->range_table = &range_digital; + s->insn_config = s626_dio_insn_config; + s->insn_bits = s626_dio_insn_bits; + + s = &dev->subdevices[3]; + /* digital I/O subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->io_bits = 0xffff; + s->private = (void *)1; /* DIO group 1 */ + s->range_table = &range_digital; + s->insn_config = s626_dio_insn_config; + s->insn_bits = s626_dio_insn_bits; + + s = &dev->subdevices[4]; + /* digital I/O subdevice */ + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->io_bits = 0xffff; + s->private = (void *)2; /* DIO group 2 */ + s->range_table = &range_digital; + s->insn_config = s626_dio_insn_config; + s->insn_bits = s626_dio_insn_bits; + + s = &dev->subdevices[5]; + /* encoder (counter) subdevice */ + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL; + s->n_chan = S626_ENCODER_CHANNELS; + s->maxdata = 0xffffff; + s->range_table = &range_unknown; + s->insn_config = s626_enc_insn_config; + s->insn_read = s626_enc_insn_read; + s->insn_write = s626_enc_insn_write; + + ret = s626_initialize(dev); + if (ret) + return ret; - /* While retaining CounterA and LatchSrc configurations, program the */ - /* new counter operating mode. */ - DEBIreplace(dev, k->MyCRA, - (uint16_t) (~(CRAMSK_INDXSRC_B | CRAMSK_CLKSRC_B)), cra); - DEBIreplace(dev, k->MyCRB, CRBMSK_CLKENAB_A | CRBMSK_LATCHSRC, crb); + return 0; } -/* Return/set a counter's enable. enab: 0=always enabled, 1=enabled by index. */ - -static void SetEnable_A(struct comedi_device *dev, struct enc_private *k, - uint16_t enab) +static void s626_detach(struct comedi_device *dev) { - DEBUG("SetEnable_A: SetEnable_A enter 3541\n"); - DEBIreplace(dev, k->MyCRB, - (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_A)), - (uint16_t) (enab << CRBBIT_CLKENAB_A)); -} + struct s626_private *devpriv = dev->private; -static void SetEnable_B(struct comedi_device *dev, struct enc_private *k, - uint16_t enab) -{ - DEBIreplace(dev, k->MyCRB, - (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_CLKENAB_B)), - (uint16_t) (enab << CRBBIT_CLKENAB_B)); -} + if (devpriv) { + /* stop ai_command */ + devpriv->ai_cmd_running = 0; -static uint16_t GetEnable_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_A) & 1; -} + if (devpriv->mmio) { + /* interrupt mask */ + /* Disable master interrupt */ + writel(0, devpriv->mmio + S626_P_IER); + /* Clear board's IRQ status flag */ + writel(S626_IRQ_GPIO3 | S626_IRQ_RPS1, + devpriv->mmio + S626_P_ISR); + + /* Disable the watchdog timer and battery charger. */ + s626_write_misc2(dev, 0); + + /* Close all interfaces on 7146 device */ + writel(S626_MC1_SHUTDOWN, devpriv->mmio + S626_P_MC1); + writel(S626_ACON1_BASE, devpriv->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); + } -static uint16_t GetEnable_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_CLKENAB_B) & 1; + if (dev->irq) + free_irq(dev->irq, dev); + if (devpriv->mmio) + iounmap(devpriv->mmio); + } + comedi_pci_disable(dev); } -/* Return/set a counter pair's latch trigger source. 0: On read - * access, 1: A index latches A, 2: B index latches B, 3: A overflow - * latches B. - */ +static struct comedi_driver s626_driver = { + .driver_name = "s626", + .module = THIS_MODULE, + .auto_attach = s626_auto_attach, + .detach = s626_detach, +}; -static void SetLatchSource(struct comedi_device *dev, struct enc_private *k, - uint16_t value) +static int s626_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) { - DEBUG("SetLatchSource: SetLatchSource enter 3550\n"); - DEBIreplace(dev, k->MyCRB, - (uint16_t) (~(CRBMSK_INTCTRL | CRBMSK_LATCHSRC)), - (uint16_t) (value << CRBBIT_LATCHSRC)); - - DEBUG("SetLatchSource: SetLatchSource exit\n"); + return comedi_pci_auto_config(dev, &s626_driver, id->driver_data); } /* - * static uint16_t GetLatchSource(struct comedi_device *dev, struct enc_private *k ) - * { - * return ( DEBIread( dev, k->MyCRB) >> CRBBIT_LATCHSRC ) & 3; - * } - */ - -/* - * Return/set the event that will trigger transfer of the preload - * register into the counter. 0=ThisCntr_Index, 1=ThisCntr_Overflow, - * 2=OverflowA (B counters only), 3=disabled. - */ - -static void SetLoadTrig_A(struct comedi_device *dev, struct enc_private *k, - uint16_t Trig) -{ - DEBIreplace(dev, k->MyCRA, (uint16_t) (~CRAMSK_LOADSRC_A), - (uint16_t) (Trig << CRABIT_LOADSRC_A)); -} - -static void SetLoadTrig_B(struct comedi_device *dev, struct enc_private *k, - uint16_t Trig) -{ - DEBIreplace(dev, k->MyCRB, - (uint16_t) (~(CRBMSK_LOADSRC_B | CRBMSK_INTCTRL)), - (uint16_t) (Trig << CRBBIT_LOADSRC_B)); -} - -static uint16_t GetLoadTrig_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRA) >> CRABIT_LOADSRC_A) & 3; -} - -static uint16_t GetLoadTrig_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_LOADSRC_B) & 3; -} - -/* Return/set counter interrupt source and clear any captured - * index/overflow events. IntSource: 0=Disabled, 1=OverflowOnly, - * 2=IndexOnly, 3=IndexAndOverflow. + * For devices with vendor:device id == 0x1131:0x7146 you must specify + * also subvendor:subdevice ids, because otherwise it will conflict with + * Philips SAA7146 media/dvb based cards. */ +static const struct pci_device_id s626_pci_table[] = { + { PCI_DEVICE_SUB(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146, + 0x6000, 0x0272) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, s626_pci_table); -static void SetIntSrc_A(struct comedi_device *dev, struct enc_private *k, - uint16_t IntSource) -{ - /* Reset any pending counter overflow or index captures. */ - DEBIreplace(dev, k->MyCRB, (uint16_t) (~CRBMSK_INTCTRL), - CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A); - - /* Program counter interrupt source. */ - DEBIreplace(dev, k->MyCRA, ~CRAMSK_INTSRC_A, - (uint16_t) (IntSource << CRABIT_INTSRC_A)); - - /* Update MISC2 interrupt enable mask. */ - devpriv->CounterIntEnabs = - (devpriv->CounterIntEnabs & ~k-> - MyEventBits[3]) | k->MyEventBits[IntSource]; -} - -static void SetIntSrc_B(struct comedi_device *dev, struct enc_private *k, - uint16_t IntSource) -{ - uint16_t crb; - - /* Cache writeable CRB register image. */ - crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL; - - /* Reset any pending counter overflow or index captures. */ - DEBIwrite(dev, k->MyCRB, - (uint16_t) (crb | CRBMSK_INTRESETCMD | CRBMSK_INTRESET_B)); - - /* Program counter interrupt source. */ - DEBIwrite(dev, k->MyCRB, - (uint16_t) ((crb & ~CRBMSK_INTSRC_B) | (IntSource << - CRBBIT_INTSRC_B))); - - /* Update MISC2 interrupt enable mask. */ - devpriv->CounterIntEnabs = - (devpriv->CounterIntEnabs & ~k-> - MyEventBits[3]) | k->MyEventBits[IntSource]; -} - -static uint16_t GetIntSrc_A(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRA) >> CRABIT_INTSRC_A) & 3; -} - -static uint16_t GetIntSrc_B(struct comedi_device *dev, struct enc_private *k) -{ - return (DEBIread(dev, k->MyCRB) >> CRBBIT_INTSRC_B) & 3; -} - -/* Return/set the clock multiplier. */ - -/* static void SetClkMult(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKMULT ) | ( value << STDBIT_CLKMULT ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkMult(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKMULT ) & 3; */ -/* } */ - -/* Return/set the clock polarity. */ - -/* static void SetClkPol( struct comedi_device *dev,struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKPOL ) | ( value << STDBIT_CLKPOL ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkPol(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKPOL ) & 1; */ -/* } */ - -/* Return/set the clock source. */ - -/* static void SetClkSrc( struct comedi_device *dev,struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_CLKSRC ) | ( value << STDBIT_CLKSRC ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetClkSrc( struct comedi_device *dev,struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_CLKSRC ) & 3; */ -/* } */ - -/* Return/set the index polarity. */ - -/* static void SetIndexPol(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXPOL ) | ( (value != 0) << STDBIT_INDXPOL ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetIndexPol(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_INDXPOL ) & 1; */ -/* } */ - -/* Return/set the index source. */ - -/* static void SetIndexSrc(struct comedi_device *dev, struct enc_private *k, uint16_t value ) */ -/* { */ -/* DEBUG("SetIndexSrc: set index src enter 3700\n"); */ -/* k->SetMode(dev, k, (uint16_t)( ( k->GetMode(dev, k ) & ~STDMSK_INDXSRC ) | ( (value != 0) << STDBIT_INDXSRC ) ), FALSE ); */ -/* } */ - -/* static uint16_t GetIndexSrc(struct comedi_device *dev, struct enc_private *k ) */ -/* { */ -/* return ( k->GetMode(dev, k ) >> STDBIT_INDXSRC ) & 1; */ -/* } */ - -/* Generate an index pulse. */ - -static void PulseIndex_A(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t cra; - - DEBUG("PulseIndex_A: pulse index enter\n"); - - cra = DEBIread(dev, k->MyCRA); /* Pulse index. */ - DEBIwrite(dev, k->MyCRA, (uint16_t) (cra ^ CRAMSK_INDXPOL_A)); - DEBUG("PulseIndex_A: pulse index step1\n"); - DEBIwrite(dev, k->MyCRA, cra); -} - -static void PulseIndex_B(struct comedi_device *dev, struct enc_private *k) -{ - register uint16_t crb; - - crb = DEBIread(dev, k->MyCRB) & ~CRBMSK_INTCTRL; /* Pulse index. */ - DEBIwrite(dev, k->MyCRB, (uint16_t) (crb ^ CRBMSK_INDXPOL_B)); - DEBIwrite(dev, k->MyCRB, crb); -} - -/* Write value into counter preload register. */ - -static void Preload(struct comedi_device *dev, struct enc_private *k, - uint32_t value) -{ - DEBUG("Preload: preload enter\n"); - DEBIwrite(dev, (uint16_t) (k->MyLatchLsw), (uint16_t) value); /* Write value to preload register. */ - DEBUG("Preload: preload step 1\n"); - DEBIwrite(dev, (uint16_t) (k->MyLatchLsw + 2), - (uint16_t) (value >> 16)); -} - -static void CountersInit(struct comedi_device *dev) -{ - int chan; - struct enc_private *k; - uint16_t Setup = (LOADSRC_INDX << BF_LOADSRC) | /* Preload upon */ - /* index. */ - (INDXSRC_SOFT << BF_INDXSRC) | /* Disable hardware index. */ - (CLKSRC_COUNTER << BF_CLKSRC) | /* Operating mode is counter. */ - (CLKPOL_POS << BF_CLKPOL) | /* Active high clock. */ - (CNTDIR_UP << BF_CLKPOL) | /* Count direction is up. */ - (CLKMULT_1X << BF_CLKMULT) | /* Clock multiplier is 1x. */ - (CLKENAB_INDEX << BF_CLKENAB); /* Enabled by index */ - - /* Disable all counter interrupts and clear any captured counter events. */ - for (chan = 0; chan < S626_ENCODER_CHANNELS; chan++) { - k = &encpriv[chan]; - k->SetMode(dev, k, Setup, TRUE); - k->SetIntSrc(dev, k, 0); - k->ResetCapFlags(dev, k); - k->SetEnable(dev, k, CLKENAB_ALWAYS); - } - DEBUG("CountersInit: counters initialized\n"); +static struct pci_driver s626_pci_driver = { + .name = "s626", + .id_table = s626_pci_table, + .probe = s626_pci_probe, + .remove = comedi_pci_auto_unconfig, +}; +module_comedi_pci_driver(s626_driver, s626_pci_driver); -} +MODULE_AUTHOR("Gianluca Palli <gpalli@deis.unibo.it>"); +MODULE_DESCRIPTION("Sensoray 626 Comedi driver module"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h index 2d1afecbbb6..33b72739c1c 100644 --- a/drivers/staging/comedi/drivers/s626.h +++ b/drivers/staging/comedi/drivers/s626.h @@ -1,727 +1,774 @@ /* - comedi/drivers/s626.h - Sensoray s626 Comedi driver, header file - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - Based on Sensoray Model 626 Linux driver Version 0.2 - Copyright (C) 2002-2004 Sensoray Co., Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -/* - Driver: s626.o (s626.ko) - Description: Sensoray 626 driver - Devices: Sensoray s626 - Authors: Gianluca Palli <gpalli@deis.unibo.it>, - Updated: Thu, 12 Jul 2005 - Status: experimental - - Configuration Options: - analog input: - none - - analog output: - none - - digital channel: - s626 has 3 dio subdevices (2,3 and 4) each with 16 i/o channels - supported configuration options: - INSN_CONFIG_DIO_QUERY - COMEDI_INPUT - COMEDI_OUTPUT - - encoder: - Every channel must be configured before reading. - - Example code - - insn.insn=INSN_CONFIG; // configuration instruction - insn.n=1; // number of operation (must be 1) - insn.data=&initialvalue; // initial value loaded into encoder - // during configuration - insn.subdev=5; // encoder subdevice - insn.chanspec=CR_PACK(encoder_channel,0,AREF_OTHER); // encoder_channel - // to configure - - comedi_do_insn(cf,&insn); // executing configuration -*/ - -#ifdef _DEBUG_ -#define DEBUG(...); printk(__VA_ARGS__); -#else -#define DEBUG(...) -#endif - -#if !defined(TRUE) -#define TRUE (1) -#endif - -#if !defined(FALSE) -#define FALSE (0) -#endif - -#if !defined(INLINE) -#define INLINE static __inline -#endif - -#include<linux/slab.h> - -#define S626_SIZE 0x0200 -#define SIZEOF_ADDRESS_SPACE 0x0200 -#define DMABUF_SIZE 4096 /* 4k pages */ + * comedi/drivers/s626.h + * Sensoray s626 Comedi driver, header file + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * Based on Sensoray Model 626 Linux driver Version 0.2 + * Copyright (C) 2002-2004 Sensoray Co., Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef S626_H_INCLUDED +#define S626_H_INCLUDED + +#define S626_DMABUF_SIZE 4096 /* 4k pages */ #define S626_ADC_CHANNELS 16 #define S626_DAC_CHANNELS 4 #define S626_ENCODER_CHANNELS 6 #define S626_DIO_CHANNELS 48 -#define S626_DIO_BANKS 3 /* Number of DIO groups. */ -#define S626_DIO_EXTCHANS 40 /* Number of */ - /* extended-capability */ - /* DIO channels. */ - -#define NUM_TRIMDACS 12 /* Number of valid TrimDAC channels. */ +#define S626_DIO_BANKS 3 /* Number of DIO groups. */ +#define S626_DIO_EXTCHANS 40 /* Number of extended-capability + * DIO channels. */ -/* PCI bus interface types. */ -#define INTEL 1 /* Intel bus type. */ -#define MOTOROLA 2 /* Motorola bus type. */ +#define S626_NUM_TRIMDACS 12 /* Number of valid TrimDAC channels. */ -#define PLATFORM INTEL /* *** SELECT PLATFORM TYPE *** */ +/* PCI bus interface types. */ +#define S626_INTEL 1 /* Intel bus type. */ +#define S626_MOTOROLA 2 /* Motorola bus type. */ -#define RANGE_5V 0x10 /* +/-5V range */ -#define RANGE_10V 0x00 /* +/-10V range */ +#define S626_PLATFORM S626_INTEL /* *** SELECT PLATFORM TYPE *** */ -#define EOPL 0x80 /* End of ADC poll list marker. */ -#define GSEL_BIPOLAR5V 0x00F0 /* LP_GSEL setting for 5V bipolar range. */ -#define GSEL_BIPOLAR10V 0x00A0 /* LP_GSEL setting for 10V bipolar range. */ +#define S626_RANGE_5V 0x10 /* +/-5V range */ +#define S626_RANGE_10V 0x00 /* +/-10V range */ -/* Error codes that must be visible to this base class. */ -#define ERR_ILLEGAL_PARM 0x00010000 /* Illegal function parameter value was specified. */ -#define ERR_I2C 0x00020000 /* I2C error. */ -#define ERR_COUNTERSETUP 0x00200000 /* Illegal setup specified for counter channel. */ -#define ERR_DEBI_TIMEOUT 0x00400000 /* DEBI transfer timed out. */ +#define S626_EOPL 0x80 /* End of ADC poll list marker. */ +#define S626_GSEL_BIPOLAR5V 0x00F0 /* S626_LP_GSEL setting 5V bipolar. */ +#define S626_GSEL_BIPOLAR10V 0x00A0 /* S626_LP_GSEL setting 10V bipolar. */ -/* Organization (physical order) and size (in DWORDs) of logical DMA buffers contained by ANA_DMABUF. */ -#define ADC_DMABUF_DWORDS 40 /* ADC DMA buffer must hold 16 samples, plus pre/post garbage samples. */ -#define DAC_WDMABUF_DWORDS 1 /* DAC output DMA buffer holds a single sample. */ +/* Error codes that must be visible to this base class. */ +#define S626_ERR_ILLEGAL_PARM 0x00010000 /* Illegal function parameter + * value was specified. */ +#define S626_ERR_I2C 0x00020000 /* I2C error. */ +#define S626_ERR_COUNTERSETUP 0x00200000 /* Illegal setup specified for + * counter channel. */ +#define S626_ERR_DEBI_TIMEOUT 0x00400000 /* DEBI transfer timed out. */ -/* All remaining space in 4KB DMA buffer is available for the RPS1 program. */ - -/* Address offsets, in DWORDS, from base of DMA buffer. */ -#define DAC_WDMABUF_OS ADC_DMABUF_DWORDS - -/* Interrupt enab bit in ISR and IER. */ -#define IRQ_GPIO3 0x00000040 /* IRQ enable for GPIO3. */ -#define IRQ_RPS1 0x10000000 -#define ISR_AFOU 0x00000800 +/* + * Organization (physical order) and size (in DWORDs) of logical DMA buffers + * contained by ANA_DMABUF. + */ +#define S626_ADC_DMABUF_DWORDS 40 /* ADC DMA buffer must hold 16 samples, + * plus pre/post garbage samples. */ +#define S626_DAC_WDMABUF_DWORDS 1 /* DAC output DMA buffer holds a single + * sample. */ + +/* All remaining space in 4KB DMA buffer is available for the RPS1 program. */ + +/* Address offsets, in DWORDS, from base of DMA buffer. */ +#define S626_DAC_WDMABUF_OS S626_ADC_DMABUF_DWORDS + +/* Interrupt enable bit in ISR and IER. */ +#define S626_IRQ_GPIO3 0x00000040 /* IRQ enable for GPIO3. */ +#define S626_IRQ_RPS1 0x10000000 +#define S626_ISR_AFOU 0x00000800 /* Audio fifo under/overflow detected. */ -#define IRQ_COINT1A 0x0400 /* conter 1A overflow interrupt mask */ -#define IRQ_COINT1B 0x0800 /* conter 1B overflow interrupt mask */ -#define IRQ_COINT2A 0x1000 /* conter 2A overflow interrupt mask */ -#define IRQ_COINT2B 0x2000 /* conter 2B overflow interrupt mask */ -#define IRQ_COINT3A 0x4000 /* conter 3A overflow interrupt mask */ -#define IRQ_COINT3B 0x8000 /* conter 3B overflow interrupt mask */ - -/* RPS command codes. */ -#define RPS_CLRSIGNAL 0x00000000 /* CLEAR SIGNAL */ -#define RPS_SETSIGNAL 0x10000000 /* SET SIGNAL */ -#define RPS_NOP 0x00000000 /* NOP */ -#define RPS_PAUSE 0x20000000 /* PAUSE */ -#define RPS_UPLOAD 0x40000000 /* UPLOAD */ -#define RPS_JUMP 0x80000000 /* JUMP */ -#define RPS_LDREG 0x90000100 /* LDREG (1 uint32_t only) */ -#define RPS_STREG 0xA0000100 /* STREG (1 uint32_t only) */ -#define RPS_STOP 0x50000000 /* STOP */ -#define RPS_IRQ 0x60000000 /* IRQ */ - -#define RPS_LOGICAL_OR 0x08000000 /* Logical OR conditionals. */ -#define RPS_INVERT 0x04000000 /* Test for negated semaphores. */ -#define RPS_DEBI 0x00000002 /* DEBI done */ - -#define RPS_SIG0 0x00200000 /* RPS semaphore 0 (used by ADC). */ -#define RPS_SIG1 0x00400000 /* RPS semaphore 1 (used by DAC). */ -#define RPS_SIG2 0x00800000 /* RPS semaphore 2 (not used). */ -#define RPS_GPIO2 0x00080000 /* RPS GPIO2 */ -#define RPS_GPIO3 0x00100000 /* RPS GPIO3 */ - -#define RPS_SIGADC RPS_SIG0 /* Trigger/status for ADC's RPS program. */ -#define RPS_SIGDAC RPS_SIG1 /* Trigger/status for DAC's RPS program. */ - -/* RPS clock parameters. */ -#define RPSCLK_SCALAR 8 /* This is apparent ratio of PCI/RPS clks (undocumented!!). */ -#define RPSCLK_PER_US (33 / RPSCLK_SCALAR) /* Number of RPS clocks in one microsecond. */ - -/* Event counter source addresses. */ -#define SBA_RPS_A0 0x27 /* Time of RPS0 busy, in PCI clocks. */ - -/* GPIO constants. */ -#define GPIO_BASE 0x10004000 /* GPIO 0,2,3 = inputs, GPIO3 = IRQ; GPIO1 = out. */ -#define GPIO1_LO 0x00000000 /* GPIO1 set to LOW. */ -#define GPIO1_HI 0x00001000 /* GPIO1 set to HIGH. */ - -/* Primary Status Register (PSR) constants. */ -#define PSR_DEBI_E 0x00040000 /* DEBI event flag. */ -#define PSR_DEBI_S 0x00080000 /* DEBI status flag. */ -#define PSR_A2_IN 0x00008000 /* Audio output DMA2 protection address reached. */ -#define PSR_AFOU 0x00000800 /* Audio FIFO under/overflow detected. */ -#define PSR_GPIO2 0x00000020 /* GPIO2 input pin: 0=AdcBusy, 1=AdcIdle. */ -#define PSR_EC0S 0x00000001 /* Event counter 0 threshold reached. */ - -/* Secondary Status Register (SSR) constants. */ -#define SSR_AF2_OUT 0x00000200 /* Audio 2 output FIFO under/overflow detected. */ - -/* Master Control Register 1 (MC1) constants. */ -#define MC1_SOFT_RESET 0x80000000 /* Invoke 7146 soft reset. */ -#define MC1_SHUTDOWN 0x3FFF0000 /* Shut down all MC1-controlled enables. */ - -#define MC1_ERPS1 0x2000 /* enab/disable RPS task 1. */ -#define MC1_ERPS0 0x1000 /* enab/disable RPS task 0. */ -#define MC1_DEBI 0x0800 /* enab/disable DEBI pins. */ -#define MC1_AUDIO 0x0200 /* enab/disable audio port pins. */ -#define MC1_I2C 0x0100 /* enab/disable I2C interface. */ -#define MC1_A2OUT 0x0008 /* enab/disable transfer on A2 out. */ -#define MC1_A2IN 0x0004 /* enab/disable transfer on A2 in. */ -#define MC1_A1IN 0x0001 /* enab/disable transfer on A1 in. */ - -/* Master Control Register 2 (MC2) constants. */ -#define MC2_UPLD_DEBIq 0x00020002 /* Upload DEBI registers. */ -#define MC2_UPLD_IICq 0x00010001 /* Upload I2C registers. */ -#define MC2_RPSSIG2_ONq 0x20002000 /* Assert RPS_SIG2. */ -#define MC2_RPSSIG1_ONq 0x10001000 /* Assert RPS_SIG1. */ -#define MC2_RPSSIG0_ONq 0x08000800 /* Assert RPS_SIG0. */ -#define MC2_UPLD_DEBI_MASKq 0x00000002 /* Upload DEBI mask. */ -#define MC2_UPLD_IIC_MASKq 0x00000001 /* Upload I2C mask. */ -#define MC2_RPSSIG2_MASKq 0x00002000 /* RPS_SIG2 bit mask. */ -#define MC2_RPSSIG1_MASKq 0x00001000 /* RPS_SIG1 bit mask. */ -#define MC2_RPSSIG0_MASKq 0x00000800 /* RPS_SIG0 bit mask. */ - -#define MC2_DELAYTRIG_4USq MC2_RPSSIG1_ON -#define MC2_DELAYBUSY_4USq MC2_RPSSIG1_MASK - -#define MC2_DELAYTRIG_6USq MC2_RPSSIG2_ON -#define MC2_DELAYBUSY_6USq MC2_RPSSIG2_MASK - -#define MC2_UPLD_DEBI 0x0002 /* Upload DEBI. */ -#define MC2_UPLD_IIC 0x0001 /* Upload I2C. */ -#define MC2_RPSSIG2 0x2000 /* RPS signal 2 (not used). */ -#define MC2_RPSSIG1 0x1000 /* RPS signal 1 (DAC RPS busy). */ -#define MC2_RPSSIG0 0x0800 /* RPS signal 0 (ADC RPS busy). */ - -#define MC2_ADC_RPS MC2_RPSSIG0 /* ADC RPS busy. */ -#define MC2_DAC_RPS MC2_RPSSIG1 /* DAC RPS busy. */ - -/* ***** oldies ***** */ -#define MC2_UPLD_DEBIQ 0x00020002 /* Upload DEBI registers. */ -#define MC2_UPLD_IICQ 0x00010001 /* Upload I2C registers. */ - -/* PCI BUS (SAA7146) REGISTER ADDRESS OFFSETS */ -#define P_PCI_BT_A 0x004C /* Audio DMA burst/threshold control. */ -#define P_DEBICFG 0x007C /* DEBI configuration. */ -#define P_DEBICMD 0x0080 /* DEBI command. */ -#define P_DEBIPAGE 0x0084 /* DEBI page. */ -#define P_DEBIAD 0x0088 /* DEBI target address. */ -#define P_I2CCTRL 0x008C /* I2C control. */ -#define P_I2CSTAT 0x0090 /* I2C status. */ -#define P_BASEA2_IN 0x00AC /* Audio input 2 base physical DMAbuf +#define S626_IRQ_COINT1A 0x0400 /* counter 1A overflow interrupt mask */ +#define S626_IRQ_COINT1B 0x0800 /* counter 1B overflow interrupt mask */ +#define S626_IRQ_COINT2A 0x1000 /* counter 2A overflow interrupt mask */ +#define S626_IRQ_COINT2B 0x2000 /* counter 2B overflow interrupt mask */ +#define S626_IRQ_COINT3A 0x4000 /* counter 3A overflow interrupt mask */ +#define S626_IRQ_COINT3B 0x8000 /* counter 3B overflow interrupt mask */ + +/* RPS command codes. */ +#define S626_RPS_CLRSIGNAL 0x00000000 /* CLEAR SIGNAL */ +#define S626_RPS_SETSIGNAL 0x10000000 /* SET SIGNAL */ +#define S626_RPS_NOP 0x00000000 /* NOP */ +#define S626_RPS_PAUSE 0x20000000 /* PAUSE */ +#define S626_RPS_UPLOAD 0x40000000 /* UPLOAD */ +#define S626_RPS_JUMP 0x80000000 /* JUMP */ +#define S626_RPS_LDREG 0x90000100 /* LDREG (1 uint32_t only) */ +#define S626_RPS_STREG 0xA0000100 /* STREG (1 uint32_t only) */ +#define S626_RPS_STOP 0x50000000 /* STOP */ +#define S626_RPS_IRQ 0x60000000 /* IRQ */ + +#define S626_RPS_LOGICAL_OR 0x08000000 /* Logical OR conditionals. */ +#define S626_RPS_INVERT 0x04000000 /* Test for negated + * semaphores. */ +#define S626_RPS_DEBI 0x00000002 /* DEBI done */ + +#define S626_RPS_SIG0 0x00200000 /* RPS semaphore 0 + * (used by ADC). */ +#define S626_RPS_SIG1 0x00400000 /* RPS semaphore 1 + * (used by DAC). */ +#define S626_RPS_SIG2 0x00800000 /* RPS semaphore 2 + * (not used). */ +#define S626_RPS_GPIO2 0x00080000 /* RPS GPIO2 */ +#define S626_RPS_GPIO3 0x00100000 /* RPS GPIO3 */ + +#define S626_RPS_SIGADC S626_RPS_SIG0 /* Trigger/status for + * ADC's RPS program. */ +#define S626_RPS_SIGDAC S626_RPS_SIG1 /* Trigger/status for + * DAC's RPS program. */ + +/* RPS clock parameters. */ +#define S626_RPSCLK_SCALAR 8 /* This is apparent ratio of + * PCI/RPS clks (undocumented!!). */ +#define S626_RPSCLK_PER_US (33 / S626_RPSCLK_SCALAR) + /* Number of RPS clocks in one + * microsecond. */ + +/* Event counter source addresses. */ +#define S626_SBA_RPS_A0 0x27 /* Time of RPS0 busy, in PCI clocks. */ + +/* GPIO constants. */ +#define S626_GPIO_BASE 0x10004000 /* GPIO 0,2,3 = inputs, + * GPIO3 = IRQ; GPIO1 = out. */ +#define S626_GPIO1_LO 0x00000000 /* GPIO1 set to LOW. */ +#define S626_GPIO1_HI 0x00001000 /* GPIO1 set to HIGH. */ + +/* Primary Status Register (PSR) constants. */ +#define S626_PSR_DEBI_E 0x00040000 /* DEBI event flag. */ +#define S626_PSR_DEBI_S 0x00080000 /* DEBI status flag. */ +#define S626_PSR_A2_IN 0x00008000 /* Audio output DMA2 protection + * address reached. */ +#define S626_PSR_AFOU 0x00000800 /* Audio FIFO under/overflow + * detected. */ +#define S626_PSR_GPIO2 0x00000020 /* GPIO2 input pin: 0=AdcBusy, + * 1=AdcIdle. */ +#define S626_PSR_EC0S 0x00000001 /* Event counter 0 threshold + * reached. */ + +/* Secondary Status Register (SSR) constants. */ +#define S626_SSR_AF2_OUT 0x00000200 /* Audio 2 output FIFO + * under/overflow detected. */ + +/* Master Control Register 1 (MC1) constants. */ +#define S626_MC1_SOFT_RESET 0x80000000 /* Invoke 7146 soft reset. */ +#define S626_MC1_SHUTDOWN 0x3FFF0000 /* Shut down all MC1-controlled + * enables. */ + +#define S626_MC1_ERPS1 0x2000 /* Enab/disable RPS task 1. */ +#define S626_MC1_ERPS0 0x1000 /* Enab/disable RPS task 0. */ +#define S626_MC1_DEBI 0x0800 /* Enab/disable DEBI pins. */ +#define S626_MC1_AUDIO 0x0200 /* Enab/disable audio port pins. */ +#define S626_MC1_I2C 0x0100 /* Enab/disable I2C interface. */ +#define S626_MC1_A2OUT 0x0008 /* Enab/disable transfer on A2 out. */ +#define S626_MC1_A2IN 0x0004 /* Enab/disable transfer on A2 in. */ +#define S626_MC1_A1IN 0x0001 /* Enab/disable transfer on A1 in. */ + +/* Master Control Register 2 (MC2) constants. */ +#define S626_MC2_UPLD_DEBI 0x0002 /* Upload DEBI. */ +#define S626_MC2_UPLD_IIC 0x0001 /* Upload I2C. */ +#define S626_MC2_RPSSIG2 0x2000 /* RPS signal 2 (not used). */ +#define S626_MC2_RPSSIG1 0x1000 /* RPS signal 1 (DAC RPS busy). */ +#define S626_MC2_RPSSIG0 0x0800 /* RPS signal 0 (ADC RPS busy). */ + +#define S626_MC2_ADC_RPS S626_MC2_RPSSIG0 /* ADC RPS busy. */ +#define S626_MC2_DAC_RPS S626_MC2_RPSSIG1 /* DAC RPS busy. */ + +/* PCI BUS (SAA7146) REGISTER ADDRESS OFFSETS */ +#define S626_P_PCI_BT_A 0x004C /* Audio DMA burst/threshold control. */ +#define S626_P_DEBICFG 0x007C /* DEBI configuration. */ +#define S626_P_DEBICMD 0x0080 /* DEBI command. */ +#define S626_P_DEBIPAGE 0x0084 /* DEBI page. */ +#define S626_P_DEBIAD 0x0088 /* DEBI target address. */ +#define S626_P_I2CCTRL 0x008C /* I2C control. */ +#define S626_P_I2CSTAT 0x0090 /* I2C status. */ +#define S626_P_BASEA2_IN 0x00AC /* Audio input 2 base physical DMAbuf * address. */ -#define P_PROTA2_IN 0x00B0 /* Audio input 2 physical DMAbuf +#define S626_P_PROTA2_IN 0x00B0 /* Audio input 2 physical DMAbuf * protection address. */ -#define P_PAGEA2_IN 0x00B4 /* Audio input 2 paging attributes. */ -#define P_BASEA2_OUT 0x00B8 /* Audio output 2 base physical DMAbuf +#define S626_P_PAGEA2_IN 0x00B4 /* Audio input 2 paging attributes. */ +#define S626_P_BASEA2_OUT 0x00B8 /* Audio output 2 base physical DMAbuf * address. */ -#define P_PROTA2_OUT 0x00BC /* Audio output 2 physical DMAbuf +#define S626_P_PROTA2_OUT 0x00BC /* Audio output 2 physical DMAbuf * protection address. */ -#define P_PAGEA2_OUT 0x00C0 /* Audio output 2 paging attributes. */ -#define P_RPSPAGE0 0x00C4 /* RPS0 page. */ -#define P_RPSPAGE1 0x00C8 /* RPS1 page. */ -#define P_RPS0_TOUT 0x00D4 /* RPS0 time-out. */ -#define P_RPS1_TOUT 0x00D8 /* RPS1 time-out. */ -#define P_IER 0x00DC /* Interrupt enable. */ -#define P_GPIO 0x00E0 /* General-purpose I/O. */ -#define P_EC1SSR 0x00E4 /* Event counter set 1 source select. */ -#define P_ECT1R 0x00EC /* Event counter threshold set 1. */ -#define P_ACON1 0x00F4 /* Audio control 1. */ -#define P_ACON2 0x00F8 /* Audio control 2. */ -#define P_MC1 0x00FC /* Master control 1. */ -#define P_MC2 0x0100 /* Master control 2. */ -#define P_RPSADDR0 0x0104 /* RPS0 instruction pointer. */ -#define P_RPSADDR1 0x0108 /* RPS1 instruction pointer. */ -#define P_ISR 0x010C /* Interrupt status. */ -#define P_PSR 0x0110 /* Primary status. */ -#define P_SSR 0x0114 /* Secondary status. */ -#define P_EC1R 0x0118 /* Event counter set 1. */ -#define P_ADP4 0x0138 /* Logical audio DMA pointer of audio +#define S626_P_PAGEA2_OUT 0x00C0 /* Audio output 2 paging attributes. */ +#define S626_P_RPSPAGE0 0x00C4 /* RPS0 page. */ +#define S626_P_RPSPAGE1 0x00C8 /* RPS1 page. */ +#define S626_P_RPS0_TOUT 0x00D4 /* RPS0 time-out. */ +#define S626_P_RPS1_TOUT 0x00D8 /* RPS1 time-out. */ +#define S626_P_IER 0x00DC /* Interrupt enable. */ +#define S626_P_GPIO 0x00E0 /* General-purpose I/O. */ +#define S626_P_EC1SSR 0x00E4 /* Event counter set 1 source select. */ +#define S626_P_ECT1R 0x00EC /* Event counter threshold set 1. */ +#define S626_P_ACON1 0x00F4 /* Audio control 1. */ +#define S626_P_ACON2 0x00F8 /* Audio control 2. */ +#define S626_P_MC1 0x00FC /* Master control 1. */ +#define S626_P_MC2 0x0100 /* Master control 2. */ +#define S626_P_RPSADDR0 0x0104 /* RPS0 instruction pointer. */ +#define S626_P_RPSADDR1 0x0108 /* RPS1 instruction pointer. */ +#define S626_P_ISR 0x010C /* Interrupt status. */ +#define S626_P_PSR 0x0110 /* Primary status. */ +#define S626_P_SSR 0x0114 /* Secondary status. */ +#define S626_P_EC1R 0x0118 /* Event counter set 1. */ +#define S626_P_ADP4 0x0138 /* Logical audio DMA pointer of audio * input FIFO A2_IN. */ -#define P_FB_BUFFER1 0x0144 /* Audio feedback buffer 1. */ -#define P_FB_BUFFER2 0x0148 /* Audio feedback buffer 2. */ -#define P_TSL1 0x0180 /* Audio time slot list 1. */ -#define P_TSL2 0x01C0 /* Audio time slot list 2. */ - -/* LOCAL BUS (GATE ARRAY) REGISTER ADDRESS OFFSETS */ -/* Analog I/O registers: */ -#define LP_DACPOL 0x0082 /* Write DAC polarity. */ -#define LP_GSEL 0x0084 /* Write ADC gain. */ -#define LP_ISEL 0x0086 /* Write ADC channel select. */ -/* Digital I/O (write only): */ -#define LP_WRINTSELA 0x0042 /* Write A interrupt enable. */ -#define LP_WREDGSELA 0x0044 /* Write A edge selection. */ -#define LP_WRCAPSELA 0x0046 /* Write A capture enable. */ -#define LP_WRDOUTA 0x0048 /* Write A digital output. */ -#define LP_WRINTSELB 0x0052 /* Write B interrupt enable. */ -#define LP_WREDGSELB 0x0054 /* Write B edge selection. */ -#define LP_WRCAPSELB 0x0056 /* Write B capture enable. */ -#define LP_WRDOUTB 0x0058 /* Write B digital output. */ -#define LP_WRINTSELC 0x0062 /* Write C interrupt enable. */ -#define LP_WREDGSELC 0x0064 /* Write C edge selection. */ -#define LP_WRCAPSELC 0x0066 /* Write C capture enable. */ -#define LP_WRDOUTC 0x0068 /* Write C digital output. */ - -/* Digital I/O (read only): */ -#define LP_RDDINA 0x0040 /* Read digital input. */ -#define LP_RDCAPFLGA 0x0048 /* Read edges captured. */ -#define LP_RDINTSELA 0x004A /* Read interrupt enable register. */ -#define LP_RDEDGSELA 0x004C /* Read edge selection register. */ -#define LP_RDCAPSELA 0x004E /* Read capture enable register. */ -#define LP_RDDINB 0x0050 /* Read digital input. */ -#define LP_RDCAPFLGB 0x0058 /* Read edges captured. */ -#define LP_RDINTSELB 0x005A /* Read interrupt enable register. */ -#define LP_RDEDGSELB 0x005C /* Read edge selection register. */ -#define LP_RDCAPSELB 0x005E /* Read capture enable register. */ -#define LP_RDDINC 0x0060 /* Read digital input. */ -#define LP_RDCAPFLGC 0x0068 /* Read edges captured. */ -#define LP_RDINTSELC 0x006A /* Read interrupt enable register. */ -#define LP_RDEDGSELC 0x006C /* Read edge selection register. */ -#define LP_RDCAPSELC 0x006E /* Read capture enable register. */ - -/* Counter Registers (read/write): */ -#define LP_CR0A 0x0000 /* 0A setup register. */ -#define LP_CR0B 0x0002 /* 0B setup register. */ -#define LP_CR1A 0x0004 /* 1A setup register. */ -#define LP_CR1B 0x0006 /* 1B setup register. */ -#define LP_CR2A 0x0008 /* 2A setup register. */ -#define LP_CR2B 0x000A /* 2B setup register. */ - -/* Counter PreLoad (write) and Latch (read) Registers: */ -#define LP_CNTR0ALSW 0x000C /* 0A lsw. */ -#define LP_CNTR0AMSW 0x000E /* 0A msw. */ -#define LP_CNTR0BLSW 0x0010 /* 0B lsw. */ -#define LP_CNTR0BMSW 0x0012 /* 0B msw. */ -#define LP_CNTR1ALSW 0x0014 /* 1A lsw. */ -#define LP_CNTR1AMSW 0x0016 /* 1A msw. */ -#define LP_CNTR1BLSW 0x0018 /* 1B lsw. */ -#define LP_CNTR1BMSW 0x001A /* 1B msw. */ -#define LP_CNTR2ALSW 0x001C /* 2A lsw. */ -#define LP_CNTR2AMSW 0x001E /* 2A msw. */ -#define LP_CNTR2BLSW 0x0020 /* 2B lsw. */ -#define LP_CNTR2BMSW 0x0022 /* 2B msw. */ - -/* Miscellaneous Registers (read/write): */ -#define LP_MISC1 0x0088 /* Read/write Misc1. */ -#define LP_WRMISC2 0x0090 /* Write Misc2. */ -#define LP_RDMISC2 0x0082 /* Read Misc2. */ - -/* Bit masks for MISC1 register that are the same for reads and writes. */ -#define MISC1_WENABLE 0x8000 /* enab writes to MISC2 (except Clear +#define S626_P_FB_BUFFER1 0x0144 /* Audio feedback buffer 1. */ +#define S626_P_FB_BUFFER2 0x0148 /* Audio feedback buffer 2. */ +#define S626_P_TSL1 0x0180 /* Audio time slot list 1. */ +#define S626_P_TSL2 0x01C0 /* Audio time slot list 2. */ + +/* LOCAL BUS (GATE ARRAY) REGISTER ADDRESS OFFSETS */ +/* Analog I/O registers: */ +#define S626_LP_DACPOL 0x0082 /* Write DAC polarity. */ +#define S626_LP_GSEL 0x0084 /* Write ADC gain. */ +#define S626_LP_ISEL 0x0086 /* Write ADC channel select. */ + +/* Digital I/O registers */ +#define S626_LP_RDDIN(x) (0x0040 + (x) * 0x10) /* R: digital input */ +#define S626_LP_WRINTSEL(x) (0x0042 + (x) * 0x10) /* W: int enable */ +#define S626_LP_WREDGSEL(x) (0x0044 + (x) * 0x10) /* W: edge selection */ +#define S626_LP_WRCAPSEL(x) (0x0046 + (x) * 0x10) /* W: capture enable */ +#define S626_LP_RDCAPFLG(x) (0x0048 + (x) * 0x10) /* R: edges captured */ +#define S626_LP_WRDOUT(x) (0x0048 + (x) * 0x10) /* W: digital output */ +#define S626_LP_RDINTSEL(x) (0x004a + (x) * 0x10) /* R: int enable */ +#define S626_LP_RDEDGSEL(x) (0x004c + (x) * 0x10) /* R: edge selection */ +#define S626_LP_RDCAPSEL(x) (0x004e + (x) * 0x10) /* R: capture enable */ + +/* Counter Registers (read/write): */ +#define S626_LP_CR0A 0x0000 /* 0A setup register. */ +#define S626_LP_CR0B 0x0002 /* 0B setup register. */ +#define S626_LP_CR1A 0x0004 /* 1A setup register. */ +#define S626_LP_CR1B 0x0006 /* 1B setup register. */ +#define S626_LP_CR2A 0x0008 /* 2A setup register. */ +#define S626_LP_CR2B 0x000A /* 2B setup register. */ + +/* Counter PreLoad (write) and Latch (read) Registers: */ +#define S626_LP_CNTR0ALSW 0x000C /* 0A lsw. */ +#define S626_LP_CNTR0AMSW 0x000E /* 0A msw. */ +#define S626_LP_CNTR0BLSW 0x0010 /* 0B lsw. */ +#define S626_LP_CNTR0BMSW 0x0012 /* 0B msw. */ +#define S626_LP_CNTR1ALSW 0x0014 /* 1A lsw. */ +#define S626_LP_CNTR1AMSW 0x0016 /* 1A msw. */ +#define S626_LP_CNTR1BLSW 0x0018 /* 1B lsw. */ +#define S626_LP_CNTR1BMSW 0x001A /* 1B msw. */ +#define S626_LP_CNTR2ALSW 0x001C /* 2A lsw. */ +#define S626_LP_CNTR2AMSW 0x001E /* 2A msw. */ +#define S626_LP_CNTR2BLSW 0x0020 /* 2B lsw. */ +#define S626_LP_CNTR2BMSW 0x0022 /* 2B msw. */ + +/* Miscellaneous Registers (read/write): */ +#define S626_LP_MISC1 0x0088 /* Read/write Misc1. */ +#define S626_LP_WRMISC2 0x0090 /* Write Misc2. */ +#define S626_LP_RDMISC2 0x0082 /* Read Misc2. */ + +/* Bit masks for MISC1 register that are the same for reads and writes. */ +#define S626_MISC1_WENABLE 0x8000 /* enab writes to MISC2 (except Clear * Watchdog bit). */ -#define MISC1_WDISABLE 0x0000 /* Disable writes to MISC2. */ -#define MISC1_EDCAP 0x1000 /* enab edge capture on DIO chans - * specified by LP_WRCAPSELx. */ -#define MISC1_NOEDCAP 0x0000 /* Disable edge capture on specified +#define S626_MISC1_WDISABLE 0x0000 /* Disable writes to MISC2. */ +#define S626_MISC1_EDCAP 0x1000 /* Enable edge capture on DIO chans + * specified by S626_LP_WRCAPSELx. */ +#define S626_MISC1_NOEDCAP 0x0000 /* Disable edge capture on specified * DIO chans. */ -/* Bit masks for MISC1 register reads. */ -#define RDMISC1_WDTIMEOUT 0x4000 /* Watchdog timer timed out. */ - -/* Bit masks for MISC2 register writes. */ -#define WRMISC2_WDCLEAR 0x8000 /* Reset watchdog timer to zero. */ -#define WRMISC2_CHARGE_ENABLE 0x4000 /* enab battery trickle charging. */ - -/* Bit masks for MISC2 register that are the same for reads and writes. */ -#define MISC2_BATT_ENABLE 0x0008 /* Backup battery enable. */ -#define MISC2_WDENABLE 0x0004 /* Watchdog timer enable. */ -#define MISC2_WDPERIOD_MASK 0x0003 /* Watchdog interval */ - /* select mask. */ - -/* Bit masks for ACON1 register. */ -#define A2_RUN 0x40000000 /* Run A2 based on TSL2. */ -#define A1_RUN 0x20000000 /* Run A1 based on TSL1. */ -#define A1_SWAP 0x00200000 /* Use big-endian for A1. */ -#define A2_SWAP 0x00100000 /* Use big-endian for A2. */ -#define WS_MODES 0x00019999 /* WS0 = TSL1 trigger */ - /* input, WS1-WS4 = */ - /* CS* outputs. */ - -#if PLATFORM == INTEL /* Base ACON1 config: always run A1 based - * on TSL1. */ -#define ACON1_BASE (WS_MODES | A1_RUN) -#elif PLATFORM == MOTOROLA -#define ACON1_BASE (WS_MODES | A1_RUN | A1_SWAP | A2_SWAP) +/* Bit masks for MISC1 register reads. */ +#define S626_RDMISC1_WDTIMEOUT 0x4000 /* Watchdog timer timed out. */ + +/* Bit masks for MISC2 register writes. */ +#define S626_WRMISC2_WDCLEAR 0x8000 /* Reset watchdog timer to zero. */ +#define S626_WRMISC2_CHARGE_ENABLE 0x4000 /* Enable battery trickle charging. */ + +/* Bit masks for MISC2 register that are the same for reads and writes. */ +#define S626_MISC2_BATT_ENABLE 0x0008 /* Backup battery enable. */ +#define S626_MISC2_WDENABLE 0x0004 /* Watchdog timer enable. */ +#define S626_MISC2_WDPERIOD_MASK 0x0003 /* Watchdog interval select mask. */ + +/* Bit masks for ACON1 register. */ +#define S626_A2_RUN 0x40000000 /* Run A2 based on TSL2. */ +#define S626_A1_RUN 0x20000000 /* Run A1 based on TSL1. */ +#define S626_A1_SWAP 0x00200000 /* Use big-endian for A1. */ +#define S626_A2_SWAP 0x00100000 /* Use big-endian for A2. */ +#define S626_WS_MODES 0x00019999 /* WS0 = TSL1 trigger input, + * WS1-WS4 = CS* outputs. */ + +#if S626_PLATFORM == S626_INTEL /* Base ACON1 config: always run + * A1 based on TSL1. */ +#define S626_ACON1_BASE (S626_WS_MODES | S626_A1_RUN) +#elif S626_PLATFORM == S626_MOTOROLA +#define S626_ACON1_BASE \ + (S626_WS_MODES | S626_A1_RUN | S626_A1_SWAP | S626_A2_SWAP) #endif -#define ACON1_ADCSTART ACON1_BASE /* Start ADC: run A1 - * based on TSL1. */ -#define ACON1_DACSTART (ACON1_BASE | A2_RUN) +#define S626_ACON1_ADCSTART S626_ACON1_BASE /* Start ADC: run A1 + * based on TSL1. */ +#define S626_ACON1_DACSTART (S626_ACON1_BASE | S626_A2_RUN) /* Start transmit to DAC: run A2 based on TSL2. */ -#define ACON1_DACSTOP ACON1_BASE /* Halt A2. */ - -/* Bit masks for ACON2 register. */ -#define A1_CLKSRC_BCLK1 0x00000000 /* A1 bit rate = BCLK1 (ADC). */ -#define A2_CLKSRC_X1 0x00800000 /* A2 bit rate = ACLK/1 (DACs). */ -#define A2_CLKSRC_X2 0x00C00000 /* A2 bit rate = ACLK/2 (DACs). */ -#define A2_CLKSRC_X4 0x01400000 /* A2 bit rate = ACLK/4 (DACs). */ -#define INVERT_BCLK2 0x00100000 /* Invert BCLK2 (DACs). */ -#define BCLK2_OE 0x00040000 /* enab BCLK2 (DACs). */ -#define ACON2_XORMASK 0x000C0000 /* XOR mask for ACON2 */ - /* active-low bits. */ - -#define ACON2_INIT (ACON2_XORMASK ^ (A1_CLKSRC_BCLK1 | A2_CLKSRC_X2 | INVERT_BCLK2 | BCLK2_OE)) - -/* Bit masks for timeslot records. */ -#define WS1 0x40000000 /* WS output to assert. */ -#define WS2 0x20000000 -#define WS3 0x10000000 -#define WS4 0x08000000 -#define RSD1 0x01000000 /* Shift A1 data in on SD1. */ -#define SDW_A1 0x00800000 /* Store rcv'd char at next - * char slot of DWORD1 buffer. */ -#define SIB_A1 0x00400000 /* Store rcv'd char at next +#define S626_ACON1_DACSTOP S626_ACON1_BASE /* Halt A2. */ + +/* Bit masks for ACON2 register. */ +#define S626_A1_CLKSRC_BCLK1 0x00000000 /* A1 bit rate = BCLK1 (ADC). */ +#define S626_A2_CLKSRC_X1 0x00800000 /* A2 bit rate = ACLK/1 + * (DACs). */ +#define S626_A2_CLKSRC_X2 0x00C00000 /* A2 bit rate = ACLK/2 + * (DACs). */ +#define S626_A2_CLKSRC_X4 0x01400000 /* A2 bit rate = ACLK/4 + * (DACs). */ +#define S626_INVERT_BCLK2 0x00100000 /* Invert BCLK2 (DACs). */ +#define S626_BCLK2_OE 0x00040000 /* Enable BCLK2 (DACs). */ +#define S626_ACON2_XORMASK 0x000C0000 /* XOR mask for ACON2 + * active-low bits. */ + +#define S626_ACON2_INIT (S626_ACON2_XORMASK ^ \ + (S626_A1_CLKSRC_BCLK1 | S626_A2_CLKSRC_X2 | \ + S626_INVERT_BCLK2 | S626_BCLK2_OE)) + +/* Bit masks for timeslot records. */ +#define S626_WS1 0x40000000 /* WS output to assert. */ +#define S626_WS2 0x20000000 +#define S626_WS3 0x10000000 +#define S626_WS4 0x08000000 +#define S626_RSD1 0x01000000 /* Shift A1 data in on SD1. */ +#define S626_SDW_A1 0x00800000 /* Store rcv'd char at next char + * slot of DWORD1 buffer. */ +#define S626_SIB_A1 0x00400000 /* Store rcv'd char at next * char slot of FB1 buffer. */ -#define SF_A1 0x00200000 /* Write unsigned long +#define S626_SF_A1 0x00200000 /* Write unsigned long * buffer to input FIFO. */ /* Select parallel-to-serial converter's data source: */ -#define XFIFO_0 0x00000000 /* Data fifo byte 0. */ -#define XFIFO_1 0x00000010 /* Data fifo byte 1. */ -#define XFIFO_2 0x00000020 /* Data fifo byte 2. */ -#define XFIFO_3 0x00000030 /* Data fifo byte 3. */ -#define XFB0 0x00000040 /* FB_BUFFER byte 0. */ -#define XFB1 0x00000050 /* FB_BUFFER byte 1. */ -#define XFB2 0x00000060 /* FB_BUFFER byte 2. */ -#define XFB3 0x00000070 /* FB_BUFFER byte 3. */ -#define SIB_A2 0x00000200 /* Store next dword from A2's - * input shifter to FB2 buffer. */ -#define SF_A2 0x00000100 /* Store next dword from A2's +#define S626_XFIFO_0 0x00000000 /* Data fifo byte 0. */ +#define S626_XFIFO_1 0x00000010 /* Data fifo byte 1. */ +#define S626_XFIFO_2 0x00000020 /* Data fifo byte 2. */ +#define S626_XFIFO_3 0x00000030 /* Data fifo byte 3. */ +#define S626_XFB0 0x00000040 /* FB_BUFFER byte 0. */ +#define S626_XFB1 0x00000050 /* FB_BUFFER byte 1. */ +#define S626_XFB2 0x00000060 /* FB_BUFFER byte 2. */ +#define S626_XFB3 0x00000070 /* FB_BUFFER byte 3. */ +#define S626_SIB_A2 0x00000200 /* Store next dword from A2's + * input shifter to FB2 + * buffer. */ +#define S626_SF_A2 0x00000100 /* Store next dword from A2's * input shifter to its input * fifo. */ -#define LF_A2 0x00000080 /* Load next dword from A2's +#define S626_LF_A2 0x00000080 /* Load next dword from A2's * output fifo into its * output dword buffer. */ -#define XSD2 0x00000008 /* Shift data out on SD2. */ -#define RSD3 0x00001800 /* Shift data in on SD3. */ -#define RSD2 0x00001000 /* Shift data in on SD2. */ -#define LOW_A2 0x00000002 /* Drive last SD low */ - /* for 7 clks, then */ - /* tri-state. */ -#define EOS 0x00000001 /* End of superframe. */ - -/* I2C configuration constants. */ -#define I2C_CLKSEL 0x0400 -/* I2C bit rate = PCIclk/480 = 68.75 KHz. */ - -#define I2C_BITRATE 68.75 -/* I2C bus data bit rate (determined by I2C_CLKSEL) in KHz. */ - -#define I2C_WRTIME 15.0 -/* Worst case time, in msec, for EEPROM internal write op. */ - -/* I2C manifest constants. */ - -/* Max retries to wait for EEPROM write. */ -#define I2C_RETRIES (I2C_WRTIME * I2C_BITRATE / 9.0) -#define I2C_ERR 0x0002 /* I2C control/status */ - /* flag ERROR. */ -#define I2C_BUSY 0x0001 /* I2C control/status */ - /* flag BUSY. */ -#define I2C_ABORT 0x0080 /* I2C status flag ABORT. */ -#define I2C_ATTRSTART 0x3 /* I2C attribute START. */ -#define I2C_ATTRCONT 0x2 /* I2C attribute CONT. */ -#define I2C_ATTRSTOP 0x1 /* I2C attribute STOP. */ -#define I2C_ATTRNOP 0x0 /* I2C attribute NOP. */ - -/* I2C read command | EEPROM address. */ -#define I2CR (devpriv->I2CAdrs | 1) - -/* I2C write command | EEPROM address. */ -#define I2CW (devpriv->I2CAdrs) - -/* Code macros used for constructing I2C command bytes. */ -#define I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) -#define I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) -#define I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) - -/* oldest */ -#define P_DEBICFGq 0x007C /* DEBI configuration. */ -#define P_DEBICMDq 0x0080 /* DEBI command. */ -#define P_DEBIPAGEq 0x0084 /* DEBI page. */ -#define P_DEBIADq 0x0088 /* DEBI target address. */ - -#define DEBI_CFG_TOQ 0x03C00000 /* timeout (15 PCI cycles) */ -#define DEBI_CFG_FASTQ 0x10000000 /* fast mode enable */ -#define DEBI_CFG_16Q 0x00080000 /* 16-bit access enable */ -#define DEBI_CFG_INCQ 0x00040000 /* enable address increment */ -#define DEBI_CFG_TIMEROFFQ 0x00010000 /* disable timer */ -#define DEBI_CMD_RDQ 0x00050000 /* read immediate 2 bytes */ -#define DEBI_CMD_WRQ 0x00040000 /* write immediate 2 bytes */ -#define DEBI_PAGE_DISABLEQ 0x00000000 /* paging disable */ - -/* DEBI command constants. */ -#define DEBI_CMD_SIZE16 (2 << 17) /* Transfer size is */ - /* always 2 bytes. */ -#define DEBI_CMD_READ 0x00010000 /* Read operation. */ -#define DEBI_CMD_WRITE 0x00000000 /* Write operation. */ - -/* Read immediate 2 bytes. */ -#define DEBI_CMD_RDWORD (DEBI_CMD_READ | DEBI_CMD_SIZE16) - -/* Write immediate 2 bytes. */ -#define DEBI_CMD_WRWORD (DEBI_CMD_WRITE | DEBI_CMD_SIZE16) - -/* DEBI configuration constants. */ -#define DEBI_CFG_XIRQ_EN 0x80000000 /* enab external */ - /* interrupt on GPIO3. */ -#define DEBI_CFG_XRESUME 0x40000000 /* Resume block */ - /* transfer when XIRQ */ - /* deasserted. */ -#define DEBI_CFG_FAST 0x10000000 /* Fast mode enable. */ - -/* 4-bit field that specifies DEBI timeout value in PCI clock cycles: */ -#define DEBI_CFG_TOUT_BIT 22 /* Finish DEBI cycle after */ - /* this many clocks. */ - -/* 2-bit field that specifies Endian byte lane steering: */ -#define DEBI_CFG_SWAP_NONE 0x00000000 /* Straight - don't */ - /* swap any bytes */ - /* (Intel). */ -#define DEBI_CFG_SWAP_2 0x00100000 /* 2-byte swap (Motorola). */ -#define DEBI_CFG_SWAP_4 0x00200000 /* 4-byte swap. */ -#define DEBI_CFG_16 0x00080000 /* Slave is able to */ - /* serve 16-bit */ - /* cycles. */ - -#define DEBI_CFG_SLAVE16 0x00080000 /* Slave is able to */ - /* serve 16-bit */ - /* cycles. */ -#define DEBI_CFG_INC 0x00040000 /* enab address */ - /* increment for block */ - /* transfers. */ -#define DEBI_CFG_INTEL 0x00020000 /* Intel style local bus. */ -#define DEBI_CFG_TIMEROFF 0x00010000 /* Disable timer. */ - -#if PLATFORM == INTEL - -#define DEBI_TOUT 7 /* Wait 7 PCI clocks */ - /* (212 ns) before */ - /* polling RDY. */ - -/* Intel byte lane steering (pass through all byte lanes). */ -#define DEBI_SWAP DEBI_CFG_SWAP_NONE - -#elif PLATFORM == MOTOROLA - -#define DEBI_TOUT 15 /* Wait 15 PCI clocks (454 ns) */ - /* maximum before timing out. */ -#define DEBI_SWAP DEBI_CFG_SWAP_2 /* Motorola byte lane steering. */ +#define S626_XSD2 0x00000008 /* Shift data out on SD2. */ +#define S626_RSD3 0x00001800 /* Shift data in on SD3. */ +#define S626_RSD2 0x00001000 /* Shift data in on SD2. */ +#define S626_LOW_A2 0x00000002 /* Drive last SD low for 7 clks, + * then tri-state. */ +#define S626_EOS 0x00000001 /* End of superframe. */ + +/* I2C configuration constants. */ +#define S626_I2C_CLKSEL 0x0400 /* I2C bit rate = + * PCIclk/480 = 68.75 KHz. */ +#define S626_I2C_BITRATE 68.75 /* I2C bus data bit rate + * (determined by + * S626_I2C_CLKSEL) in KHz. */ +#define S626_I2C_WRTIME 15.0 /* Worst case time, in msec, + * for EEPROM internal write + * op. */ + +/* I2C manifest constants. */ + +/* Max retries to wait for EEPROM write. */ +#define S626_I2C_RETRIES (S626_I2C_WRTIME * S626_I2C_BITRATE / 9.0) +#define S626_I2C_ERR 0x0002 /* I2C control/status flag ERROR. */ +#define S626_I2C_BUSY 0x0001 /* I2C control/status flag BUSY. */ +#define S626_I2C_ABORT 0x0080 /* I2C status flag ABORT. */ +#define S626_I2C_ATTRSTART 0x3 /* I2C attribute START. */ +#define S626_I2C_ATTRCONT 0x2 /* I2C attribute CONT. */ +#define S626_I2C_ATTRSTOP 0x1 /* I2C attribute STOP. */ +#define S626_I2C_ATTRNOP 0x0 /* I2C attribute NOP. */ + +/* Code macros used for constructing I2C command bytes. */ +#define S626_I2C_B2(ATTR, VAL) (((ATTR) << 6) | ((VAL) << 24)) +#define S626_I2C_B1(ATTR, VAL) (((ATTR) << 4) | ((VAL) << 16)) +#define S626_I2C_B0(ATTR, VAL) (((ATTR) << 2) | ((VAL) << 8)) + +/* DEBI command constants. */ +#define S626_DEBI_CMD_SIZE16 (2 << 17) /* Transfer size is always + * 2 bytes. */ +#define S626_DEBI_CMD_READ 0x00010000 /* Read operation. */ +#define S626_DEBI_CMD_WRITE 0x00000000 /* Write operation. */ + +/* Read immediate 2 bytes. */ +#define S626_DEBI_CMD_RDWORD (S626_DEBI_CMD_READ | S626_DEBI_CMD_SIZE16) + +/* Write immediate 2 bytes. */ +#define S626_DEBI_CMD_WRWORD (S626_DEBI_CMD_WRITE | S626_DEBI_CMD_SIZE16) + +/* DEBI configuration constants. */ +#define S626_DEBI_CFG_XIRQ_EN 0x80000000 /* Enable external interrupt + * on GPIO3. */ +#define S626_DEBI_CFG_XRESUME 0x40000000 /* Resume block */ + /* Transfer when XIRQ + * deasserted. */ +#define S626_DEBI_CFG_TOQ 0x03C00000 /* Timeout (15 PCI cycles). */ +#define S626_DEBI_CFG_FAST 0x10000000 /* Fast mode enable. */ + +/* 4-bit field that specifies DEBI timeout value in PCI clock cycles: */ +#define S626_DEBI_CFG_TOUT_BIT 22 /* Finish DEBI cycle after this many + * clocks. */ + +/* 2-bit field that specifies Endian byte lane steering: */ +#define S626_DEBI_CFG_SWAP_NONE 0x00000000 /* Straight - don't swap any + * bytes (Intel). */ +#define S626_DEBI_CFG_SWAP_2 0x00100000 /* 2-byte swap (Motorola). */ +#define S626_DEBI_CFG_SWAP_4 0x00200000 /* 4-byte swap. */ +#define S626_DEBI_CFG_SLAVE16 0x00080000 /* Slave is able to serve + * 16-bit cycles. */ +#define S626_DEBI_CFG_INC 0x00040000 /* Enable address increment + * for block transfers. */ +#define S626_DEBI_CFG_INTEL 0x00020000 /* Intel style local bus. */ +#define S626_DEBI_CFG_TIMEROFF 0x00010000 /* Disable timer. */ + +#if S626_PLATFORM == S626_INTEL + +#define S626_DEBI_TOUT 7 /* Wait 7 PCI clocks (212 ns) before + * polling RDY. */ + +/* Intel byte lane steering (pass through all byte lanes). */ +#define S626_DEBI_SWAP S626_DEBI_CFG_SWAP_NONE + +#elif S626_PLATFORM == S626_MOTOROLA + +#define S626_DEBI_TOUT 15 /* Wait 15 PCI clocks (454 ns) maximum + * before timing out. */ + +/* Motorola byte lane steering. */ +#define S626_DEBI_SWAP S626_DEBI_CFG_SWAP_2 #endif -/* DEBI page table constants. */ -#define DEBI_PAGE_DISABLE 0x00000000 /* Paging disable. */ - -/* ******* EXTRA FROM OTHER SANSORAY * .h ******* */ - -/* LoadSrc values: */ -#define LOADSRC_INDX 0 /* Preload core in response to */ - /* Index. */ -#define LOADSRC_OVER 1 /* Preload core in response to */ - /* Overflow. */ -#define LOADSRCB_OVERA 2 /* Preload B core in response */ - /* to A Overflow. */ -#define LOADSRC_NONE 3 /* Never preload core. */ - -/* IntSrc values: */ -#define INTSRC_NONE 0 /* Interrupts disabled. */ -#define INTSRC_OVER 1 /* Interrupt on Overflow. */ -#define INTSRC_INDX 2 /* Interrupt on Index. */ -#define INTSRC_BOTH 3 /* Interrupt on Index or Overflow. */ - -/* LatchSrc values: */ -#define LATCHSRC_AB_READ 0 /* Latch on read. */ -#define LATCHSRC_A_INDXA 1 /* Latch A on A Index. */ -#define LATCHSRC_B_INDXB 2 /* Latch B on B Index. */ -#define LATCHSRC_B_OVERA 3 /* Latch B on A Overflow. */ - -/* IndxSrc values: */ -#define INDXSRC_HARD 0 /* Hardware or software index. */ -#define INDXSRC_SOFT 1 /* Software index only. */ - -/* IndxPol values: */ -#define INDXPOL_POS 0 /* Index input is active high. */ -#define INDXPOL_NEG 1 /* Index input is active low. */ - -/* ClkSrc values: */ -#define CLKSRC_COUNTER 0 /* Counter mode. */ -#define CLKSRC_TIMER 2 /* Timer mode. */ -#define CLKSRC_EXTENDER 3 /* Extender mode. */ - -/* ClkPol values: */ -#define CLKPOL_POS 0 /* Counter/Extender clock is */ - /* active high. */ -#define CLKPOL_NEG 1 /* Counter/Extender clock is */ - /* active low. */ -#define CNTDIR_UP 0 /* Timer counts up. */ -#define CNTDIR_DOWN 1 /* Timer counts down. */ - -/* ClkEnab values: */ -#define CLKENAB_ALWAYS 0 /* Clock always enabled. */ -#define CLKENAB_INDEX 1 /* Clock is enabled by index. */ - -/* ClkMult values: */ -#define CLKMULT_4X 0 /* 4x clock multiplier. */ -#define CLKMULT_2X 1 /* 2x clock multiplier. */ -#define CLKMULT_1X 2 /* 1x clock multiplier. */ - -/* Bit Field positions in COUNTER_SETUP structure: */ -#define BF_LOADSRC 9 /* Preload trigger. */ -#define BF_INDXSRC 7 /* Index source. */ -#define BF_INDXPOL 6 /* Index polarity. */ -#define BF_CLKSRC 4 /* Clock source. */ -#define BF_CLKPOL 3 /* Clock polarity/count direction. */ -#define BF_CLKMULT 1 /* Clock multiplier. */ -#define BF_CLKENAB 0 /* Clock enable. */ - -/* Enumerated counter operating modes specified by ClkSrc bit field in */ -/* a COUNTER_SETUP. */ - -#define CLKSRC_COUNTER 0 /* Counter: ENC_C clock, ENC_D */ - /* direction. */ -#define CLKSRC_TIMER 2 /* Timer: SYS_C clock, */ - /* direction specified by */ - /* ClkPol. */ -#define CLKSRC_EXTENDER 3 /* Extender: OVR_A clock, */ - /* ENC_D direction. */ - -/* Enumerated counter clock multipliers. */ - -#define MULT_X0 0x0003 /* Supports no multipliers; */ - /* fixed physical multiplier = */ - /* 3. */ -#define MULT_X1 0x0002 /* Supports multiplier x1; */ - /* fixed physical multiplier = */ - /* 2. */ -#define MULT_X2 0x0001 /* Supports multipliers x1, */ - /* x2; physical multipliers = */ - /* 1 or 2. */ -#define MULT_X4 0x0000 /* Supports multipliers x1, */ - /* x2, x4; physical */ - /* multipliers = 0, 1 or 2. */ - -/* Sanity-check limits for parameters. */ - -#define NUM_COUNTERS 6 /* Maximum valid counter */ - /* logical channel number. */ -#define NUM_INTSOURCES 4 -#define NUM_LATCHSOURCES 4 -#define NUM_CLKMULTS 4 -#define NUM_CLKSOURCES 4 -#define NUM_CLKPOLS 2 -#define NUM_INDEXPOLS 2 -#define NUM_INDEXSOURCES 2 -#define NUM_LOADTRIGS 4 - -/* Bit field positions in CRA and CRB counter control registers. */ - -/* Bit field positions in CRA: */ -#define CRABIT_INDXSRC_B 14 /* B index source. */ -#define CRABIT_CLKSRC_B 12 /* B clock source. */ -#define CRABIT_INDXPOL_A 11 /* A index polarity. */ -#define CRABIT_LOADSRC_A 9 /* A preload trigger. */ -#define CRABIT_CLKMULT_A 7 /* A clock multiplier. */ -#define CRABIT_INTSRC_A 5 /* A interrupt source. */ -#define CRABIT_CLKPOL_A 4 /* A clock polarity. */ -#define CRABIT_INDXSRC_A 2 /* A index source. */ -#define CRABIT_CLKSRC_A 0 /* A clock source. */ - -/* Bit field positions in CRB: */ -#define CRBBIT_INTRESETCMD 15 /* Interrupt reset command. */ -#define CRBBIT_INTRESET_B 14 /* B interrupt reset enable. */ -#define CRBBIT_INTRESET_A 13 /* A interrupt reset enable. */ -#define CRBBIT_CLKENAB_A 12 /* A clock enable. */ -#define CRBBIT_INTSRC_B 10 /* B interrupt source. */ -#define CRBBIT_LATCHSRC 8 /* A/B latch source. */ -#define CRBBIT_LOADSRC_B 6 /* B preload trigger. */ -#define CRBBIT_CLKMULT_B 3 /* B clock multiplier. */ -#define CRBBIT_CLKENAB_B 2 /* B clock enable. */ -#define CRBBIT_INDXPOL_B 1 /* B index polarity. */ -#define CRBBIT_CLKPOL_B 0 /* B clock polarity. */ - -/* Bit field masks for CRA and CRB. */ - -#define CRAMSK_INDXSRC_B ((uint16_t)(3 << CRABIT_INDXSRC_B)) -#define CRAMSK_CLKSRC_B ((uint16_t)(3 << CRABIT_CLKSRC_B)) -#define CRAMSK_INDXPOL_A ((uint16_t)(1 << CRABIT_INDXPOL_A)) -#define CRAMSK_LOADSRC_A ((uint16_t)(3 << CRABIT_LOADSRC_A)) -#define CRAMSK_CLKMULT_A ((uint16_t)(3 << CRABIT_CLKMULT_A)) -#define CRAMSK_INTSRC_A ((uint16_t)(3 << CRABIT_INTSRC_A)) -#define CRAMSK_CLKPOL_A ((uint16_t)(3 << CRABIT_CLKPOL_A)) -#define CRAMSK_INDXSRC_A ((uint16_t)(3 << CRABIT_INDXSRC_A)) -#define CRAMSK_CLKSRC_A ((uint16_t)(3 << CRABIT_CLKSRC_A)) - -#define CRBMSK_INTRESETCMD ((uint16_t)(1 << CRBBIT_INTRESETCMD)) -#define CRBMSK_INTRESET_B ((uint16_t)(1 << CRBBIT_INTRESET_B)) -#define CRBMSK_INTRESET_A ((uint16_t)(1 << CRBBIT_INTRESET_A)) -#define CRBMSK_CLKENAB_A ((uint16_t)(1 << CRBBIT_CLKENAB_A)) -#define CRBMSK_INTSRC_B ((uint16_t)(3 << CRBBIT_INTSRC_B)) -#define CRBMSK_LATCHSRC ((uint16_t)(3 << CRBBIT_LATCHSRC)) -#define CRBMSK_LOADSRC_B ((uint16_t)(3 << CRBBIT_LOADSRC_B)) -#define CRBMSK_CLKMULT_B ((uint16_t)(3 << CRBBIT_CLKMULT_B)) -#define CRBMSK_CLKENAB_B ((uint16_t)(1 << CRBBIT_CLKENAB_B)) -#define CRBMSK_INDXPOL_B ((uint16_t)(1 << CRBBIT_INDXPOL_B)) -#define CRBMSK_CLKPOL_B ((uint16_t)(1 << CRBBIT_CLKPOL_B)) - -#define CRBMSK_INTCTRL (CRBMSK_INTRESETCMD | CRBMSK_INTRESET_A | CRBMSK_INTRESET_B) /* Interrupt reset control bits. */ - -/* Bit field positions for standardized SETUP structure. */ - -#define STDBIT_INTSRC 13 -#define STDBIT_LATCHSRC 11 -#define STDBIT_LOADSRC 9 -#define STDBIT_INDXSRC 7 -#define STDBIT_INDXPOL 6 -#define STDBIT_CLKSRC 4 -#define STDBIT_CLKPOL 3 -#define STDBIT_CLKMULT 1 -#define STDBIT_CLKENAB 0 - -/* Bit field masks for standardized SETUP structure. */ - -#define STDMSK_INTSRC ((uint16_t)(3 << STDBIT_INTSRC)) -#define STDMSK_LATCHSRC ((uint16_t)(3 << STDBIT_LATCHSRC)) -#define STDMSK_LOADSRC ((uint16_t)(3 << STDBIT_LOADSRC)) -#define STDMSK_INDXSRC ((uint16_t)(1 << STDBIT_INDXSRC)) -#define STDMSK_INDXPOL ((uint16_t)(1 << STDBIT_INDXPOL)) -#define STDMSK_CLKSRC ((uint16_t)(3 << STDBIT_CLKSRC)) -#define STDMSK_CLKPOL ((uint16_t)(1 << STDBIT_CLKPOL)) -#define STDMSK_CLKMULT ((uint16_t)(3 << STDBIT_CLKMULT)) -#define STDMSK_CLKENAB ((uint16_t)(1 << STDBIT_CLKENAB)) - -struct bufferDMA { - dma_addr_t PhysicalBase; - void *LogicalBase; - uint32_t DMAHandle; -}; +/* DEBI page table constants. */ +#define S626_DEBI_PAGE_DISABLE 0x00000000 /* Paging disable. */ + +/* ******* EXTRA FROM OTHER SENSORAY * .h ******* */ + +/* LoadSrc values: */ +#define S626_LOADSRC_INDX 0 /* Preload core in response to Index. */ +#define S626_LOADSRC_OVER 1 /* Preload core in response to + * Overflow. */ +#define S626_LOADSRCB_OVERA 2 /* Preload B core in response to + * A Overflow. */ +#define S626_LOADSRC_NONE 3 /* Never preload core. */ + +/* IntSrc values: */ +#define S626_INTSRC_NONE 0 /* Interrupts disabled. */ +#define S626_INTSRC_OVER 1 /* Interrupt on Overflow. */ +#define S626_INTSRC_INDX 2 /* Interrupt on Index. */ +#define S626_INTSRC_BOTH 3 /* Interrupt on Index or Overflow. */ + +/* LatchSrc values: */ +#define S626_LATCHSRC_AB_READ 0 /* Latch on read. */ +#define S626_LATCHSRC_A_INDXA 1 /* Latch A on A Index. */ +#define S626_LATCHSRC_B_INDXB 2 /* Latch B on B Index. */ +#define S626_LATCHSRC_B_OVERA 3 /* Latch B on A Overflow. */ + +/* IndxSrc values: */ +#define S626_INDXSRC_ENCODER 0 /* Encoder. */ +#define S626_INDXSRC_DIGIN 1 /* Digital inputs. */ +#define S626_INDXSRC_SOFT 2 /* S/w controlled by IndxPol bit. */ +#define S626_INDXSRC_DISABLED 3 /* Index disabled. */ + +/* IndxPol values: */ +#define S626_INDXPOL_POS 0 /* Index input is active high. */ +#define S626_INDXPOL_NEG 1 /* Index input is active low. */ + +/* Logical encoder mode values: */ +#define S626_ENCMODE_COUNTER 0 /* Counter mode. */ +#define S626_ENCMODE_TIMER 2 /* Timer mode. */ +#define S626_ENCMODE_EXTENDER 3 /* Extender mode. */ + +/* Physical CntSrc values (for Counter A source and Counter B source): */ +#define S626_CNTSRC_ENCODER 0 /* Encoder */ +#define S626_CNTSRC_DIGIN 1 /* Digital inputs */ +#define S626_CNTSRC_SYSCLK 2 /* System clock up */ +#define S626_CNTSRC_SYSCLK_DOWN 3 /* System clock down */ + +/* ClkPol values: */ +#define S626_CLKPOL_POS 0 /* Counter/Extender clock is + * active high. */ +#define S626_CLKPOL_NEG 1 /* Counter/Extender clock is + * active low. */ +#define S626_CNTDIR_UP 0 /* Timer counts up. */ +#define S626_CNTDIR_DOWN 1 /* Timer counts down. */ + +/* ClkEnab values: */ +#define S626_CLKENAB_ALWAYS 0 /* Clock always enabled. */ +#define S626_CLKENAB_INDEX 1 /* Clock is enabled by index. */ + +/* ClkMult values: */ +#define S626_CLKMULT_4X 0 /* 4x clock multiplier. */ +#define S626_CLKMULT_2X 1 /* 2x clock multiplier. */ +#define S626_CLKMULT_1X 2 /* 1x clock multiplier. */ +#define S626_CLKMULT_SPECIAL 3 /* Special clock multiplier value. */ + +/* Sanity-check limits for parameters. */ + +#define S626_NUM_COUNTERS 6 /* Maximum valid counter + * logical channel number. */ +#define S626_NUM_INTSOURCES 4 +#define S626_NUM_LATCHSOURCES 4 +#define S626_NUM_CLKMULTS 4 +#define S626_NUM_CLKSOURCES 4 +#define S626_NUM_CLKPOLS 2 +#define S626_NUM_INDEXPOLS 2 +#define S626_NUM_INDEXSOURCES 2 +#define S626_NUM_LOADTRIGS 4 + +/* General macros for manipulating bitfields: */ +#define S626_MAKE(x, w, p) (((x) & ((1 << (w)) - 1)) << (p)) +#define S626_UNMAKE(v, w, p) (((v) >> (p)) & ((1 << (w)) - 1)) + +/* Bit field positions in CRA: */ +#define S626_CRABIT_INDXSRC_B 14 /* B index source. */ +#define S626_CRABIT_CNTSRC_B 12 /* B counter source. */ +#define S626_CRABIT_INDXPOL_A 11 /* A index polarity. */ +#define S626_CRABIT_LOADSRC_A 9 /* A preload trigger. */ +#define S626_CRABIT_CLKMULT_A 7 /* A clock multiplier. */ +#define S626_CRABIT_INTSRC_A 5 /* A interrupt source. */ +#define S626_CRABIT_CLKPOL_A 4 /* A clock polarity. */ +#define S626_CRABIT_INDXSRC_A 2 /* A index source. */ +#define S626_CRABIT_CNTSRC_A 0 /* A counter source. */ + +/* Bit field widths in CRA: */ +#define S626_CRAWID_INDXSRC_B 2 +#define S626_CRAWID_CNTSRC_B 2 +#define S626_CRAWID_INDXPOL_A 1 +#define S626_CRAWID_LOADSRC_A 2 +#define S626_CRAWID_CLKMULT_A 2 +#define S626_CRAWID_INTSRC_A 2 +#define S626_CRAWID_CLKPOL_A 1 +#define S626_CRAWID_INDXSRC_A 2 +#define S626_CRAWID_CNTSRC_A 2 + +/* Bit field masks for CRA: */ +#define S626_CRAMSK_INDXSRC_B S626_SET_CRA_INDXSRC_B(~0) +#define S626_CRAMSK_CNTSRC_B S626_SET_CRA_CNTSRC_B(~0) +#define S626_CRAMSK_INDXPOL_A S626_SET_CRA_INDXPOL_A(~0) +#define S626_CRAMSK_LOADSRC_A S626_SET_CRA_LOADSRC_A(~0) +#define S626_CRAMSK_CLKMULT_A S626_SET_CRA_CLKMULT_A(~0) +#define S626_CRAMSK_INTSRC_A S626_SET_CRA_INTSRC_A(~0) +#define S626_CRAMSK_CLKPOL_A S626_SET_CRA_CLKPOL_A(~0) +#define S626_CRAMSK_INDXSRC_A S626_SET_CRA_INDXSRC_A(~0) +#define S626_CRAMSK_CNTSRC_A S626_SET_CRA_CNTSRC_A(~0) + +/* Construct parts of the CRA value: */ +#define S626_SET_CRA_INDXSRC_B(x) \ + S626_MAKE((x), S626_CRAWID_INDXSRC_B, S626_CRABIT_INDXSRC_B) +#define S626_SET_CRA_CNTSRC_B(x) \ + S626_MAKE((x), S626_CRAWID_CNTSRC_B, S626_CRABIT_CNTSRC_B) +#define S626_SET_CRA_INDXPOL_A(x) \ + S626_MAKE((x), S626_CRAWID_INDXPOL_A, S626_CRABIT_INDXPOL_A) +#define S626_SET_CRA_LOADSRC_A(x) \ + S626_MAKE((x), S626_CRAWID_LOADSRC_A, S626_CRABIT_LOADSRC_A) +#define S626_SET_CRA_CLKMULT_A(x) \ + S626_MAKE((x), S626_CRAWID_CLKMULT_A, S626_CRABIT_CLKMULT_A) +#define S626_SET_CRA_INTSRC_A(x) \ + S626_MAKE((x), S626_CRAWID_INTSRC_A, S626_CRABIT_INTSRC_A) +#define S626_SET_CRA_CLKPOL_A(x) \ + S626_MAKE((x), S626_CRAWID_CLKPOL_A, S626_CRABIT_CLKPOL_A) +#define S626_SET_CRA_INDXSRC_A(x) \ + S626_MAKE((x), S626_CRAWID_INDXSRC_A, S626_CRABIT_INDXSRC_A) +#define S626_SET_CRA_CNTSRC_A(x) \ + S626_MAKE((x), S626_CRAWID_CNTSRC_A, S626_CRABIT_CNTSRC_A) + +/* Extract parts of the CRA value: */ +#define S626_GET_CRA_INDXSRC_B(v) \ + S626_UNMAKE((v), S626_CRAWID_INDXSRC_B, S626_CRABIT_INDXSRC_B) +#define S626_GET_CRA_CNTSRC_B(v) \ + S626_UNMAKE((v), S626_CRAWID_CNTSRC_B, S626_CRABIT_CNTSRC_B) +#define S626_GET_CRA_INDXPOL_A(v) \ + S626_UNMAKE((v), S626_CRAWID_INDXPOL_A, S626_CRABIT_INDXPOL_A) +#define S626_GET_CRA_LOADSRC_A(v) \ + S626_UNMAKE((v), S626_CRAWID_LOADSRC_A, S626_CRABIT_LOADSRC_A) +#define S626_GET_CRA_CLKMULT_A(v) \ + S626_UNMAKE((v), S626_CRAWID_CLKMULT_A, S626_CRABIT_CLKMULT_A) +#define S626_GET_CRA_INTSRC_A(v) \ + S626_UNMAKE((v), S626_CRAWID_INTSRC_A, S626_CRABIT_INTSRC_A) +#define S626_GET_CRA_CLKPOL_A(v) \ + S626_UNMAKE((v), S626_CRAWID_CLKPOL_A, S626_CRABIT_CLKPOL_A) +#define S626_GET_CRA_INDXSRC_A(v) \ + S626_UNMAKE((v), S626_CRAWID_INDXSRC_A, S626_CRABIT_INDXSRC_A) +#define S626_GET_CRA_CNTSRC_A(v) \ + S626_UNMAKE((v), S626_CRAWID_CNTSRC_A, S626_CRABIT_CNTSRC_A) + +/* Bit field positions in CRB: */ +#define S626_CRBBIT_INTRESETCMD 15 /* (w) Interrupt reset command. */ +#define S626_CRBBIT_CNTDIR_B 15 /* (r) B counter direction. */ +#define S626_CRBBIT_INTRESET_B 14 /* (w) B interrupt reset enable. */ +#define S626_CRBBIT_OVERDO_A 14 /* (r) A overflow routed to dig. out. */ +#define S626_CRBBIT_INTRESET_A 13 /* (w) A interrupt reset enable. */ +#define S626_CRBBIT_OVERDO_B 13 /* (r) B overflow routed to dig. out. */ +#define S626_CRBBIT_CLKENAB_A 12 /* A clock enable. */ +#define S626_CRBBIT_INTSRC_B 10 /* B interrupt source. */ +#define S626_CRBBIT_LATCHSRC 8 /* A/B latch source. */ +#define S626_CRBBIT_LOADSRC_B 6 /* B preload trigger. */ +#define S626_CRBBIT_CLEAR_B 7 /* B cleared when A overflows. */ +#define S626_CRBBIT_CLKMULT_B 3 /* B clock multiplier. */ +#define S626_CRBBIT_CLKENAB_B 2 /* B clock enable. */ +#define S626_CRBBIT_INDXPOL_B 1 /* B index polarity. */ +#define S626_CRBBIT_CLKPOL_B 0 /* B clock polarity. */ + +/* Bit field widths in CRB: */ +#define S626_CRBWID_INTRESETCMD 1 +#define S626_CRBWID_CNTDIR_B 1 +#define S626_CRBWID_INTRESET_B 1 +#define S626_CRBWID_OVERDO_A 1 +#define S626_CRBWID_INTRESET_A 1 +#define S626_CRBWID_OVERDO_B 1 +#define S626_CRBWID_CLKENAB_A 1 +#define S626_CRBWID_INTSRC_B 2 +#define S626_CRBWID_LATCHSRC 2 +#define S626_CRBWID_LOADSRC_B 2 +#define S626_CRBWID_CLEAR_B 1 +#define S626_CRBWID_CLKMULT_B 2 +#define S626_CRBWID_CLKENAB_B 1 +#define S626_CRBWID_INDXPOL_B 1 +#define S626_CRBWID_CLKPOL_B 1 + +/* Bit field masks for CRB: */ +#define S626_CRBMSK_INTRESETCMD S626_SET_CRB_INTRESETCMD(~0) /* (w) */ +#define S626_CRBMSK_CNTDIR_B S626_CRBMSK_INTRESETCMD /* (r) */ +#define S626_CRBMSK_INTRESET_B S626_SET_CRB_INTRESET_B(~0) /* (w) */ +#define S626_CRBMSK_OVERDO_A S626_CRBMSK_INTRESET_B /* (r) */ +#define S626_CRBMSK_INTRESET_A S626_SET_CRB_INTRESET_A(~0) /* (w) */ +#define S626_CRBMSK_OVERDO_B S626_CRBMSK_INTRESET_A /* (r) */ +#define S626_CRBMSK_CLKENAB_A S626_SET_CRB_CLKENAB_A(~0) +#define S626_CRBMSK_INTSRC_B S626_SET_CRB_INTSRC_B(~0) +#define S626_CRBMSK_LATCHSRC S626_SET_CRB_LATCHSRC(~0) +#define S626_CRBMSK_LOADSRC_B S626_SET_CRB_LOADSRC_B(~0) +#define S626_CRBMSK_CLEAR_B S626_SET_CRB_CLEAR_B(~0) +#define S626_CRBMSK_CLKMULT_B S626_SET_CRB_CLKMULT_B(~0) +#define S626_CRBMSK_CLKENAB_B S626_SET_CRB_CLKENAB_B(~0) +#define S626_CRBMSK_INDXPOL_B S626_SET_CRB_INDXPOL_B(~0) +#define S626_CRBMSK_CLKPOL_B S626_SET_CRB_CLKPOL_B(~0) + +/* Interrupt reset control bits. */ +#define S626_CRBMSK_INTCTRL (S626_CRBMSK_INTRESETCMD | \ + S626_CRBMSK_INTRESET_A | \ + S626_CRBMSK_INTRESET_B) + +/* Construct parts of the CRB value: */ +#define S626_SET_CRB_INTRESETCMD(x) \ + S626_MAKE((x), S626_CRBWID_INTRESETCMD, S626_CRBBIT_INTRESETCMD) +#define S626_SET_CRB_INTRESET_B(x) \ + S626_MAKE((x), S626_CRBWID_INTRESET_B, S626_CRBBIT_INTRESET_B) +#define S626_SET_CRB_INTRESET_A(x) \ + S626_MAKE((x), S626_CRBWID_INTRESET_A, S626_CRBBIT_INTRESET_A) +#define S626_SET_CRB_CLKENAB_A(x) \ + S626_MAKE((x), S626_CRBWID_CLKENAB_A, S626_CRBBIT_CLKENAB_A) +#define S626_SET_CRB_INTSRC_B(x) \ + S626_MAKE((x), S626_CRBWID_INTSRC_B, S626_CRBBIT_INTSRC_B) +#define S626_SET_CRB_LATCHSRC(x) \ + S626_MAKE((x), S626_CRBWID_LATCHSRC, S626_CRBBIT_LATCHSRC) +#define S626_SET_CRB_LOADSRC_B(x) \ + S626_MAKE((x), S626_CRBWID_LOADSRC_B, S626_CRBBIT_LOADSRC_B) +#define S626_SET_CRB_CLEAR_B(x) \ + S626_MAKE((x), S626_CRBWID_CLEAR_B, S626_CRBBIT_CLEAR_B) +#define S626_SET_CRB_CLKMULT_B(x) \ + S626_MAKE((x), S626_CRBWID_CLKMULT_B, S626_CRBBIT_CLKMULT_B) +#define S626_SET_CRB_CLKENAB_B(x) \ + S626_MAKE((x), S626_CRBWID_CLKENAB_B, S626_CRBBIT_CLKENAB_B) +#define S626_SET_CRB_INDXPOL_B(x) \ + S626_MAKE((x), S626_CRBWID_INDXPOL_B, S626_CRBBIT_INDXPOL_B) +#define S626_SET_CRB_CLKPOL_B(x) \ + S626_MAKE((x), S626_CRBWID_CLKPOL_B, S626_CRBBIT_CLKPOL_B) + +/* Extract parts of the CRB value: */ +#define S626_GET_CRB_CNTDIR_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CNTDIR_B, S626_CRBBIT_CNTDIR_B) +#define S626_GET_CRB_OVERDO_A(v) \ + S626_UNMAKE((v), S626_CRBWID_OVERDO_A, S626_CRBBIT_OVERDO_A) +#define S626_GET_CRB_OVERDO_B(v) \ + S626_UNMAKE((v), S626_CRBWID_OVERDO_B, S626_CRBBIT_OVERDO_B) +#define S626_GET_CRB_CLKENAB_A(v) \ + S626_UNMAKE((v), S626_CRBWID_CLKENAB_A, S626_CRBBIT_CLKENAB_A) +#define S626_GET_CRB_INTSRC_B(v) \ + S626_UNMAKE((v), S626_CRBWID_INTSRC_B, S626_CRBBIT_INTSRC_B) +#define S626_GET_CRB_LATCHSRC(v) \ + S626_UNMAKE((v), S626_CRBWID_LATCHSRC, S626_CRBBIT_LATCHSRC) +#define S626_GET_CRB_LOADSRC_B(v) \ + S626_UNMAKE((v), S626_CRBWID_LOADSRC_B, S626_CRBBIT_LOADSRC_B) +#define S626_GET_CRB_CLEAR_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CLEAR_B, S626_CRBBIT_CLEAR_B) +#define S626_GET_CRB_CLKMULT_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CLKMULT_B, S626_CRBBIT_CLKMULT_B) +#define S626_GET_CRB_CLKENAB_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CLKENAB_B, S626_CRBBIT_CLKENAB_B) +#define S626_GET_CRB_INDXPOL_B(v) \ + S626_UNMAKE((v), S626_CRBWID_INDXPOL_B, S626_CRBBIT_INDXPOL_B) +#define S626_GET_CRB_CLKPOL_B(v) \ + S626_UNMAKE((v), S626_CRBWID_CLKPOL_B, S626_CRBBIT_CLKPOL_B) + +/* Bit field positions for standardized SETUP structure: */ +#define S626_STDBIT_INTSRC 13 +#define S626_STDBIT_LATCHSRC 11 +#define S626_STDBIT_LOADSRC 9 +#define S626_STDBIT_INDXSRC 7 +#define S626_STDBIT_INDXPOL 6 +#define S626_STDBIT_ENCMODE 4 +#define S626_STDBIT_CLKPOL 3 +#define S626_STDBIT_CLKMULT 1 +#define S626_STDBIT_CLKENAB 0 + +/* Bit field widths for standardized SETUP structure: */ +#define S626_STDWID_INTSRC 2 +#define S626_STDWID_LATCHSRC 2 +#define S626_STDWID_LOADSRC 2 +#define S626_STDWID_INDXSRC 2 +#define S626_STDWID_INDXPOL 1 +#define S626_STDWID_ENCMODE 2 +#define S626_STDWID_CLKPOL 1 +#define S626_STDWID_CLKMULT 2 +#define S626_STDWID_CLKENAB 1 + +/* Bit field masks for standardized SETUP structure: */ +#define S626_STDMSK_INTSRC S626_SET_STD_INTSRC(~0) +#define S626_STDMSK_LATCHSRC S626_SET_STD_LATCHSRC(~0) +#define S626_STDMSK_LOADSRC S626_SET_STD_LOADSRC(~0) +#define S626_STDMSK_INDXSRC S626_SET_STD_INDXSRC(~0) +#define S626_STDMSK_INDXPOL S626_SET_STD_INDXPOL(~0) +#define S626_STDMSK_ENCMODE S626_SET_STD_ENCMODE(~0) +#define S626_STDMSK_CLKPOL S626_SET_STD_CLKPOL(~0) +#define S626_STDMSK_CLKMULT S626_SET_STD_CLKMULT(~0) +#define S626_STDMSK_CLKENAB S626_SET_STD_CLKENAB(~0) + +/* Construct parts of standardized SETUP structure: */ +#define S626_SET_STD_INTSRC(x) \ + S626_MAKE((x), S626_STDWID_INTSRC, S626_STDBIT_INTSRC) +#define S626_SET_STD_LATCHSRC(x) \ + S626_MAKE((x), S626_STDWID_LATCHSRC, S626_STDBIT_LATCHSRC) +#define S626_SET_STD_LOADSRC(x) \ + S626_MAKE((x), S626_STDWID_LOADSRC, S626_STDBIT_LOADSRC) +#define S626_SET_STD_INDXSRC(x) \ + S626_MAKE((x), S626_STDWID_INDXSRC, S626_STDBIT_INDXSRC) +#define S626_SET_STD_INDXPOL(x) \ + S626_MAKE((x), S626_STDWID_INDXPOL, S626_STDBIT_INDXPOL) +#define S626_SET_STD_ENCMODE(x) \ + S626_MAKE((x), S626_STDWID_ENCMODE, S626_STDBIT_ENCMODE) +#define S626_SET_STD_CLKPOL(x) \ + S626_MAKE((x), S626_STDWID_CLKPOL, S626_STDBIT_CLKPOL) +#define S626_SET_STD_CLKMULT(x) \ + S626_MAKE((x), S626_STDWID_CLKMULT, S626_STDBIT_CLKMULT) +#define S626_SET_STD_CLKENAB(x) \ + S626_MAKE((x), S626_STDWID_CLKENAB, S626_STDBIT_CLKENAB) + +/* Extract parts of standardized SETUP structure: */ +#define S626_GET_STD_INTSRC(v) \ + S626_UNMAKE((v), S626_STDWID_INTSRC, S626_STDBIT_INTSRC) +#define S626_GET_STD_LATCHSRC(v) \ + S626_UNMAKE((v), S626_STDWID_LATCHSRC, S626_STDBIT_LATCHSRC) +#define S626_GET_STD_LOADSRC(v) \ + S626_UNMAKE((v), S626_STDWID_LOADSRC, S626_STDBIT_LOADSRC) +#define S626_GET_STD_INDXSRC(v) \ + S626_UNMAKE((v), S626_STDWID_INDXSRC, S626_STDBIT_INDXSRC) +#define S626_GET_STD_INDXPOL(v) \ + S626_UNMAKE((v), S626_STDWID_INDXPOL, S626_STDBIT_INDXPOL) +#define S626_GET_STD_ENCMODE(v) \ + S626_UNMAKE((v), S626_STDWID_ENCMODE, S626_STDBIT_ENCMODE) +#define S626_GET_STD_CLKPOL(v) \ + S626_UNMAKE((v), S626_STDWID_CLKPOL, S626_STDBIT_CLKPOL) +#define S626_GET_STD_CLKMULT(v) \ + S626_UNMAKE((v), S626_STDWID_CLKMULT, S626_STDBIT_CLKMULT) +#define S626_GET_STD_CLKENAB(v) \ + S626_UNMAKE((v), S626_STDWID_CLKENAB, S626_STDBIT_CLKENAB) + +#endif diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index ebfce33f0b4..441813ffb17 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* @@ -31,37 +26,18 @@ Status: in development */ +#include <linux/module.h> #include "../comedidev.h" #include <linux/delay.h> -#include <linux/ioport.h> #include <linux/sched.h> #include <linux/slab.h> -#include <asm/termios.h> +#include <linux/termios.h> #include <asm/ioctls.h> #include <linux/serial.h> #include <linux/poll.h> -/* - * 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. - */ -struct serial2002_board { - const char *name; -}; - -static const struct serial2002_board serial2002_boards[] = { - { - .name = "serial2002"} -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct serial2002_board *)dev->board_ptr) - struct serial2002_range_table_t { /* HACK... */ @@ -83,48 +59,46 @@ struct serial2002_private { struct serial2002_range_table_t in_range[32], out_range[32]; }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct serial2002_private *)dev->private) - -static int serial2002_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int serial2002_detach(struct comedi_device *dev); -struct comedi_driver driver_serial2002 = { - .driver_name = "serial2002", - .module = THIS_MODULE, - .attach = serial2002_attach, - .detach = serial2002_detach, - .board_name = &serial2002_boards[0].name, - .offset = sizeof(struct serial2002_board), - .num_names = ARRAY_SIZE(serial2002_boards), -}; - -static int serial2002_di_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int serial2002_do_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int serial2002_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int serial2002_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int serial2002_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - struct serial_data { enum { is_invalid, is_digital, is_channel } kind; int index; unsigned long value; }; -static long tty_ioctl(struct file *f, unsigned op, unsigned long param) +/* + * The configuration serial_data.value read from the device is + * a bitmask that defines specific options of a channel: + * + * 4:0 - the channel to configure + * 7:5 - the kind of channel + * 9:8 - the command used to configure the channel + * + * The remaining bits vary in use depending on the command: + * + * BITS 15:10 - the channel bits (maxdata) + * MIN/MAX 12:10 - the units multiplier for the scale + * 13 - the sign of the scale + * 33:14 - the base value for the range + */ +#define S2002_CFG_CHAN(x) ((x) & 0x1f) +#define S2002_CFG_KIND(x) (((x) >> 5) & 0x7) +#define S2002_CFG_KIND_INVALID 0 +#define S2002_CFG_KIND_DIGITAL_IN 1 +#define S2002_CFG_KIND_DIGITAL_OUT 2 +#define S2002_CFG_KIND_ANALOG_IN 3 +#define S2002_CFG_KIND_ANALOG_OUT 4 +#define S2002_CFG_KIND_ENCODER_IN 5 +#define S2002_CFG_CMD(x) (((x) >> 8) & 0x3) +#define S2002_CFG_CMD_BITS 0 +#define S2002_CFG_CMD_MIN 1 +#define S2002_CFG_CMD_MAX 2 +#define S2002_CFG_BITS(x) (((x) >> 10) & 0x3f) +#define S2002_CFG_UNITS(x) (((x) >> 10) & 0x7) +#define S2002_CFG_SIGN(x) (((x) >> 13) & 0x1) +#define S2002_CFG_BASE(x) (((x) >> 14) & 0xfffff) + +static long serial2002_tty_ioctl(struct file *f, unsigned op, + unsigned long param) { if (f->f_op->unlocked_ioctl) return f->f_op->unlocked_ioctl(f, op, param); @@ -132,39 +106,58 @@ static long tty_ioctl(struct file *f, unsigned op, unsigned long param) return -ENOSYS; } -static int tty_write(struct file *f, unsigned char *buf, int count) +static int serial2002_tty_write(struct file *f, unsigned char *buf, int count) { + const char __user *p = (__force const char __user *)buf; int result; mm_segment_t oldfs; oldfs = get_fs(); set_fs(KERNEL_DS); f->f_pos = 0; - result = f->f_op->write(f, buf, count, &f->f_pos); + result = f->f_op->write(f, p, count, &f->f_pos); set_fs(oldfs); return result; } -#if 0 -/* - * On 2.6.26.3 this occaisonally gave me page faults, worked around by - * settings.c_cc[VMIN] = 0; settings.c_cc[VTIME] = 0 - */ -static int tty_available(struct file *f) +static int serial2002_tty_readb(struct file *f, unsigned char *buf) { - long result = 0; - mm_segment_t oldfs; + char __user *p = (__force char __user *)buf; - oldfs = get_fs(); - set_fs(KERNEL_DS); - tty_ioctl(f, FIONREAD, (unsigned long)&result); - set_fs(oldfs); - return result; + f->f_pos = 0; + return f->f_op->read(f, p, 1, &f->f_pos); +} + +static void serial2002_tty_read_poll_wait(struct file *f, int timeout) +{ + struct poll_wqueues table; + struct timeval start, now; + + do_gettimeofday(&start); + poll_initwait(&table); + while (1) { + long elapsed; + int mask; + + mask = f->f_op->poll(f, &table.pt); + if (mask & (POLLRDNORM | POLLRDBAND | POLLIN | + POLLHUP | POLLERR)) { + break; + } + do_gettimeofday(&now); + elapsed = (1000000 * (now.tv_sec - start.tv_sec) + + now.tv_usec - start.tv_usec); + if (elapsed > timeout) + break; + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(((timeout - elapsed) * HZ) / 10000); + } + poll_freewait(&table); } -#endif -static int tty_read(struct file *f, int timeout) +static int serial2002_tty_read(struct file *f, int timeout) { + unsigned char ch; int result; result = -1; @@ -174,53 +167,19 @@ static int tty_read(struct file *f, int timeout) oldfs = get_fs(); set_fs(KERNEL_DS); if (f->f_op->poll) { - struct poll_wqueues table; - struct timeval start, now; + serial2002_tty_read_poll_wait(f, timeout); - do_gettimeofday(&start); - poll_initwait(&table); - while (1) { - long elapsed; - int mask; - - mask = f->f_op->poll(f, &table.pt); - if (mask & (POLLRDNORM | POLLRDBAND | POLLIN | - POLLHUP | POLLERR)) { - break; - } - do_gettimeofday(&now); - elapsed = - (1000000 * (now.tv_sec - start.tv_sec) + - now.tv_usec - start.tv_usec); - if (elapsed > timeout) { - break; - } - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(((timeout - - elapsed) * HZ) / 10000); - } - poll_freewait(&table); - { - unsigned char ch; - - f->f_pos = 0; - if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) { - result = ch; - } - } + if (serial2002_tty_readb(f, &ch) == 1) + result = ch; } else { /* Device does not support poll, busy wait */ int retries = 0; while (1) { - unsigned char ch; - retries++; - if (retries >= timeout) { + if (retries >= timeout) break; - } - f->f_pos = 0; - if (f->f_op->read(f, &ch, 1, &f->f_pos) == 1) { + if (serial2002_tty_readb(f, &ch) == 1) { result = ch; break; } @@ -232,90 +191,76 @@ static int tty_read(struct file *f, int timeout) return result; } -static void tty_setspeed(struct file *f, int speed) +static void serial2002_tty_setspeed(struct file *f, int speed) { + struct termios termios; + struct serial_struct serial; mm_segment_t oldfs; oldfs = get_fs(); set_fs(KERNEL_DS); - { - /* Set speed */ - struct termios settings; - - tty_ioctl(f, TCGETS, (unsigned long)&settings); -/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */ - settings.c_iflag = 0; - settings.c_oflag = 0; - settings.c_lflag = 0; - settings.c_cflag = CLOCAL | CS8 | CREAD; - settings.c_cc[VMIN] = 0; - settings.c_cc[VTIME] = 0; - switch (speed) { - case 2400:{ - settings.c_cflag |= B2400; - } - break; - case 4800:{ - settings.c_cflag |= B4800; - } - break; - case 9600:{ - settings.c_cflag |= B9600; - } - break; - case 19200:{ - settings.c_cflag |= B19200; - } - break; - case 38400:{ - settings.c_cflag |= B38400; - } - break; - case 57600:{ - settings.c_cflag |= B57600; - } - break; - case 115200:{ - settings.c_cflag |= B115200; - } - break; - default:{ - settings.c_cflag |= B9600; - } - break; - } - tty_ioctl(f, TCSETS, (unsigned long)&settings); -/* printk("Speed: %d\n", settings.c_cflag & (CBAUD | CBAUDEX)); */ - } - { - /* Set low latency */ - struct serial_struct settings; - tty_ioctl(f, TIOCGSERIAL, (unsigned long)&settings); - settings.flags |= ASYNC_LOW_LATENCY; - tty_ioctl(f, TIOCSSERIAL, (unsigned long)&settings); + /* Set speed */ + serial2002_tty_ioctl(f, TCGETS, (unsigned long)&termios); + termios.c_iflag = 0; + termios.c_oflag = 0; + termios.c_lflag = 0; + termios.c_cflag = CLOCAL | CS8 | CREAD; + termios.c_cc[VMIN] = 0; + termios.c_cc[VTIME] = 0; + switch (speed) { + case 2400: + termios.c_cflag |= B2400; + break; + case 4800: + termios.c_cflag |= B4800; + break; + case 9600: + termios.c_cflag |= B9600; + break; + case 19200: + termios.c_cflag |= B19200; + break; + case 38400: + termios.c_cflag |= B38400; + break; + case 57600: + termios.c_cflag |= B57600; + break; + case 115200: + termios.c_cflag |= B115200; + break; + default: + termios.c_cflag |= B9600; + break; } + serial2002_tty_ioctl(f, TCSETS, (unsigned long)&termios); + + /* Set low latency */ + serial2002_tty_ioctl(f, TIOCGSERIAL, (unsigned long)&serial); + serial.flags |= ASYNC_LOW_LATENCY; + serial2002_tty_ioctl(f, TIOCSSERIAL, (unsigned long)&serial); set_fs(oldfs); } -static void poll_digital(struct file *f, int channel) +static void serial2002_poll_digital(struct file *f, int channel) { char cmd; cmd = 0x40 | (channel & 0x1f); - tty_write(f, &cmd, 1); + serial2002_tty_write(f, &cmd, 1); } -static void poll_channel(struct file *f, int channel) +static void serial2002_poll_channel(struct file *f, int channel) { char cmd; cmd = 0x60 | (channel & 0x1f); - tty_write(f, &cmd, 1); + serial2002_tty_write(f, &cmd, 1); } -static struct serial_data serial_read(struct file *f, int timeout) +static struct serial_data serial2002_read(struct file *f, int timeout) { struct serial_data result; int length; @@ -325,26 +270,23 @@ static struct serial_data serial_read(struct file *f, int timeout) result.value = 0; length = 0; while (1) { - int data = tty_read(f, timeout); + int data = serial2002_tty_read(f, timeout); length++; if (data < 0) { - printk("serial2002 error\n"); break; } else if (data & 0x80) { result.value = (result.value << 7) | (data & 0x7f); } else { if (length == 1) { switch ((data >> 5) & 0x03) { - case 0:{ - result.value = 0; - result.kind = is_digital; - } + case 0: + result.value = 0; + result.kind = is_digital; break; - case 1:{ - result.value = 1; - result.kind = is_digital; - } + case 1: + result.value = 1; + result.kind = is_digital; break; } } else { @@ -360,12 +302,12 @@ static struct serial_data serial_read(struct file *f, int timeout) } -static void serial_write(struct file *f, struct serial_data data) +static void serial2002_write(struct file *f, struct serial_data data) { if (data.kind == is_digital) { unsigned char ch = ((data.value << 5) & 0x20) | (data.index & 0x1f); - tty_write(f, &ch, 1); + serial2002_tty_write(f, &ch, 1); } else { unsigned char ch[6]; int i = 0; @@ -389,330 +331,263 @@ static void serial_write(struct file *f, struct serial_data data) i++; ch[i] = ((data.value << 5) & 0x60) | (data.index & 0x1f); i++; - tty_write(f, ch, i); + serial2002_tty_write(f, ch, i); } } -static int serial_2002_open(struct comedi_device *dev) +struct config_t { + short int kind; + short int bits; + int min; + int max; +}; + +static int serial2002_setup_subdevice(struct comedi_subdevice *s, + struct config_t *cfg, + struct serial2002_range_table_t *range, + unsigned char *mapping, + int kind) { - int result; - char port[20]; + const struct comedi_lrange **range_table_list = NULL; + unsigned int *maxdata_list; + int j, chan; - sprintf(port, "/dev/ttyS%d", devpriv->port); - devpriv->tty = filp_open(port, O_RDWR, 0); - if (IS_ERR(devpriv->tty)) { - result = (int)PTR_ERR(devpriv->tty); - printk("serial_2002: file open error = %d\n", result); - } else { - struct config_t { - - short int kind; - short int bits; - int min; - int max; - }; - - struct config_t *dig_in_config; - struct config_t *dig_out_config; - struct config_t *chan_in_config; - struct config_t *chan_out_config; - int i; - - result = 0; - dig_in_config = kcalloc(32, sizeof(struct config_t), - GFP_KERNEL); - dig_out_config = kcalloc(32, sizeof(struct config_t), - GFP_KERNEL); - chan_in_config = kcalloc(32, sizeof(struct config_t), - GFP_KERNEL); - chan_out_config = kcalloc(32, sizeof(struct config_t), - GFP_KERNEL); - if (!dig_in_config || !dig_out_config - || !chan_in_config || !chan_out_config) { - result = -ENOMEM; - goto err_alloc_configs; + for (chan = 0, j = 0; j < 32; j++) { + if (cfg[j].kind == kind) + chan++; + } + s->n_chan = chan; + s->maxdata = 0; + kfree(s->maxdata_list); + maxdata_list = kmalloc(sizeof(unsigned int) * s->n_chan, GFP_KERNEL); + if (!maxdata_list) + return -ENOMEM; + s->maxdata_list = maxdata_list; + kfree(s->range_table_list); + s->range_table = NULL; + s->range_table_list = NULL; + if (kind == 1 || kind == 2) { + s->range_table = &range_digital; + } else if (range) { + range_table_list = + kmalloc(sizeof(struct serial2002_range_table_t) * + s->n_chan, GFP_KERNEL); + if (!range_table_list) + return -ENOMEM; + s->range_table_list = range_table_list; + } + for (chan = 0, j = 0; j < 32; j++) { + if (cfg[j].kind == kind) { + if (mapping) + mapping[chan] = j; + if (range) { + range[j].length = 1; + range[j].range.min = cfg[j].min; + range[j].range.max = cfg[j].max; + range_table_list[chan] = + (const struct comedi_lrange *)&range[j]; + } + maxdata_list[chan] = ((long long)1 << cfg[j].bits) - 1; + chan++; } + } + return 0; +} - tty_setspeed(devpriv->tty, devpriv->speed); - poll_channel(devpriv->tty, 31); /* Start reading configuration */ - while (1) { - struct serial_data data; +static int serial2002_setup_subdevs(struct comedi_device *dev) +{ + struct serial2002_private *devpriv = dev->private; + struct config_t *di_cfg; + struct config_t *do_cfg; + struct config_t *ai_cfg; + struct config_t *ao_cfg; + struct config_t *cfg; + struct comedi_subdevice *s; + int result = 0; + int i; - data = serial_read(devpriv->tty, 1000); - if (data.kind != is_channel || data.index != 31 - || !(data.value & 0xe0)) { - break; - } else { - int command, channel, kind; - struct config_t *cur_config = NULL; - - channel = data.value & 0x1f; - kind = (data.value >> 5) & 0x7; - command = (data.value >> 8) & 0x3; - switch (kind) { - case 1:{ - cur_config = dig_in_config; - } - break; - case 2:{ - cur_config = dig_out_config; - } - break; - case 3:{ - cur_config = chan_in_config; - } - break; - case 4:{ - cur_config = chan_out_config; - } - break; - case 5:{ - cur_config = chan_in_config; - } - break; - } + /* Allocate the temporary structs to hold the configuration data */ + di_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL); + do_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL); + ai_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL); + ao_cfg = kcalloc(32, sizeof(*cfg), GFP_KERNEL); + if (!di_cfg || !do_cfg || !ai_cfg || !ao_cfg) { + result = -ENOMEM; + goto err_alloc_configs; + } - if (cur_config) { - cur_config[channel].kind = kind; - switch (command) { - case 0:{ - cur_config[channel].bits - = - (data.value >> 10) & - 0x3f; - } - break; - case 1:{ - int unit, sign, min; - unit = - (data.value >> 10) & - 0x7; - sign = - (data.value >> 13) & - 0x1; - min = - (data.value >> 14) & - 0xfffff; - - switch (unit) { - case 0:{ - min = - min - * - 1000000; - } - break; - case 1:{ - min = - min - * - 1000; - } - break; - case 2:{ - min = - min - * 1; - } - break; - } - if (sign) { - min = -min; - } - cur_config[channel].min - = min; - } - break; - case 2:{ - int unit, sign, max; - unit = - (data.value >> 10) & - 0x7; - sign = - (data.value >> 13) & - 0x1; - max = - (data.value >> 14) & - 0xfffff; - - switch (unit) { - case 0:{ - max = - max - * - 1000000; - } - break; - case 1:{ - max = - max - * - 1000; - } - break; - case 2:{ - max = - max - * 1; - } - break; - } - if (sign) { - max = -max; - } - cur_config[channel].max - = max; - } - break; - } - } - } - } - for (i = 0; i <= 4; i++) { - /* Fill in subdev data */ - struct config_t *c; - unsigned char *mapping = NULL; - struct serial2002_range_table_t *range = NULL; - int kind = 0; - - switch (i) { - case 0:{ - c = dig_in_config; - mapping = devpriv->digital_in_mapping; - kind = 1; - } + /* Read the configuration from the connected device */ + serial2002_tty_setspeed(devpriv->tty, devpriv->speed); + serial2002_poll_channel(devpriv->tty, 31); + while (1) { + struct serial_data data; + + data = serial2002_read(devpriv->tty, 1000); + if (data.kind != is_channel || data.index != 31 || + S2002_CFG_KIND(data.value) == S2002_CFG_KIND_INVALID) { + break; + } else { + int channel = S2002_CFG_CHAN(data.value); + int range = S2002_CFG_BASE(data.value); + + switch (S2002_CFG_KIND(data.value)) { + case S2002_CFG_KIND_DIGITAL_IN: + cfg = di_cfg; break; - case 1:{ - c = dig_out_config; - mapping = devpriv->digital_out_mapping; - kind = 2; - } + case S2002_CFG_KIND_DIGITAL_OUT: + cfg = do_cfg; break; - case 2:{ - c = chan_in_config; - mapping = devpriv->analog_in_mapping; - range = devpriv->in_range; - kind = 3; - } + case S2002_CFG_KIND_ANALOG_IN: + cfg = ai_cfg; break; - case 3:{ - c = chan_out_config; - mapping = devpriv->analog_out_mapping; - range = devpriv->out_range; - kind = 4; - } + case S2002_CFG_KIND_ANALOG_OUT: + cfg = ao_cfg; break; - case 4:{ - c = chan_in_config; - mapping = devpriv->encoder_in_mapping; - range = devpriv->in_range; - kind = 5; - } + case S2002_CFG_KIND_ENCODER_IN: + cfg = ai_cfg; break; - default:{ - c = NULL; - } + default: + cfg = NULL; break; } - if (c) { - struct comedi_subdevice *s; - const struct comedi_lrange **range_table_list = - NULL; - unsigned int *maxdata_list; - int j, chan; - - for (chan = 0, j = 0; j < 32; j++) { - if (c[j].kind == kind) { - chan++; - } - } - s = &dev->subdevices[i]; - s->n_chan = chan; - s->maxdata = 0; - kfree(s->maxdata_list); - s->maxdata_list = maxdata_list = - kmalloc(sizeof(unsigned int) * s->n_chan, - GFP_KERNEL); - if (!s->maxdata_list) - break; /* error handled below */ - kfree(s->range_table_list); - s->range_table = NULL; - s->range_table_list = NULL; - if (range) { - s->range_table_list = range_table_list = - kmalloc(sizeof - (struct - serial2002_range_table_t) * - s->n_chan, GFP_KERNEL); - if (!s->range_table_list) - break; /* err handled below */ - } - for (chan = 0, j = 0; j < 32; j++) { - if (c[j].kind == kind) { - if (mapping) { - mapping[chan] = j; - } - if (range) { - range[j].length = 1; - range[j].range.min = - c[j].min; - range[j].range.max = - c[j].max; - range_table_list[chan] = - (const struct - comedi_lrange *) - &range[j]; - } - maxdata_list[chan] = - ((long long)1 << c[j].bits) - - 1; - chan++; - } + if (!cfg) + continue; /* unknown kind, skip it */ + + cfg[channel].kind = S2002_CFG_KIND(data.value); + + switch (S2002_CFG_CMD(data.value)) { + case S2002_CFG_CMD_BITS: + cfg[channel].bits = S2002_CFG_BITS(data.value); + break; + case S2002_CFG_CMD_MIN: + case S2002_CFG_CMD_MAX: + switch (S2002_CFG_UNITS(data.value)) { + case 0: + range *= 1000000; + break; + case 1: + range *= 1000; + break; + case 2: + range *= 1; + break; } + if (S2002_CFG_SIGN(data.value)) + range = -range; + if (S2002_CFG_CMD(data.value) == + S2002_CFG_CMD_MIN) + cfg[channel].min = range; + else + cfg[channel].max = range; + break; } } - if (i <= 4) { - /* Failed to allocate maxdata_list or range_table_list - * for a subdevice that needed it. */ - result = -ENOMEM; - for (i = 0; i <= 4; i++) { - struct comedi_subdevice *s; - - s = &dev->subdevices[i]; - kfree(s->maxdata_list); - s->maxdata_list = NULL; - kfree(s->range_table_list); - s->range_table_list = NULL; - } + } + + /* Fill in subdevice data */ + for (i = 0; i <= 4; i++) { + unsigned char *mapping = NULL; + struct serial2002_range_table_t *range = NULL; + int kind = 0; + + s = &dev->subdevices[i]; + + switch (i) { + case 0: + cfg = di_cfg; + mapping = devpriv->digital_in_mapping; + kind = S2002_CFG_KIND_DIGITAL_IN; + break; + case 1: + cfg = do_cfg; + mapping = devpriv->digital_out_mapping; + kind = S2002_CFG_KIND_DIGITAL_OUT; + break; + case 2: + cfg = ai_cfg; + mapping = devpriv->analog_in_mapping; + range = devpriv->in_range; + kind = S2002_CFG_KIND_ANALOG_IN; + break; + case 3: + cfg = ao_cfg; + mapping = devpriv->analog_out_mapping; + range = devpriv->out_range; + kind = S2002_CFG_KIND_ANALOG_OUT; + break; + case 4: + cfg = ai_cfg; + mapping = devpriv->encoder_in_mapping; + range = devpriv->in_range; + kind = S2002_CFG_KIND_ENCODER_IN; + break; } + if (serial2002_setup_subdevice(s, cfg, range, mapping, kind)) + break; /* err handled below */ + } + if (i <= 4) { + /* + * Failed to allocate maxdata_list or range_table_list + * for a subdevice that needed it. + */ + result = -ENOMEM; + for (i = 0; i <= 4; i++) { + s = &dev->subdevices[i]; + kfree(s->maxdata_list); + s->maxdata_list = NULL; + kfree(s->range_table_list); + s->range_table_list = NULL; + } + } + err_alloc_configs: - kfree(dig_in_config); - kfree(dig_out_config); - kfree(chan_in_config); - kfree(chan_out_config); - - if (result) { - if (devpriv->tty) { - filp_close(devpriv->tty, 0); - devpriv->tty = NULL; - } + kfree(di_cfg); + kfree(do_cfg); + kfree(ai_cfg); + kfree(ao_cfg); + + if (result) { + if (devpriv->tty) { + filp_close(devpriv->tty, NULL); + devpriv->tty = NULL; } } + return result; } -static void serial_2002_close(struct comedi_device *dev) +static int serial2002_open(struct comedi_device *dev) { - if (!IS_ERR(devpriv->tty) && (devpriv->tty != 0)) { - filp_close(devpriv->tty, 0); + struct serial2002_private *devpriv = dev->private; + int result; + char port[20]; + + sprintf(port, "/dev/ttyS%d", devpriv->port); + devpriv->tty = filp_open(port, O_RDWR, 0); + if (IS_ERR(devpriv->tty)) { + result = (int)PTR_ERR(devpriv->tty); + dev_err(dev->class_dev, "file open error = %d\n", result); + } else { + result = serial2002_setup_subdevs(dev); } + return result; } -static int serial2002_di_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void serial2002_close(struct comedi_device *dev) { + struct serial2002_private *devpriv = dev->private; + + if (!IS_ERR(devpriv->tty) && devpriv->tty) + filp_close(devpriv->tty, NULL); +} + +static int serial2002_di_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct serial2002_private *devpriv = dev->private; int n; int chan; @@ -720,22 +595,23 @@ static int serial2002_di_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { struct serial_data read; - poll_digital(devpriv->tty, chan); + serial2002_poll_digital(devpriv->tty, chan); while (1) { - read = serial_read(devpriv->tty, 1000); - if (read.kind != is_digital || read.index == chan) { + read = serial2002_read(devpriv->tty, 1000); + if (read.kind != is_digital || read.index == chan) break; - } } data[n] = read.value; } return n; } -static int serial2002_do_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int serial2002_do_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct serial2002_private *devpriv = dev->private; int n; int chan; @@ -746,15 +622,17 @@ static int serial2002_do_winsn(struct comedi_device *dev, write.kind = is_digital; write.index = chan; write.value = data[n]; - serial_write(devpriv->tty, write); + serial2002_write(devpriv->tty, write); } return n; } -static int serial2002_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int serial2002_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct serial2002_private *devpriv = dev->private; int n; int chan; @@ -762,22 +640,23 @@ static int serial2002_ai_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { struct serial_data read; - poll_channel(devpriv->tty, chan); + serial2002_poll_channel(devpriv->tty, chan); while (1) { - read = serial_read(devpriv->tty, 1000); - if (read.kind != is_channel || read.index == chan) { + read = serial2002_read(devpriv->tty, 1000); + if (read.kind != is_channel || read.index == chan) break; - } } data[n] = read.value; } return n; } -static int serial2002_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int serial2002_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct serial2002_private *devpriv = dev->private; int n; int chan; @@ -788,30 +667,33 @@ static int serial2002_ao_winsn(struct comedi_device *dev, write.kind = is_channel; write.index = chan; write.value = data[n]; - serial_write(devpriv->tty, write); + serial2002_write(devpriv->tty, write); devpriv->ao_readback[chan] = data[n]; } return n; } -static int serial2002_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int serial2002_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct serial2002_private *devpriv = dev->private; int n; int chan = CR_CHAN(insn->chanspec); - for (n = 0; n < insn->n; n++) { + for (n = 0; n < insn->n; n++) data[n] = devpriv->ao_readback[chan]; - } return n; } -static int serial2002_ei_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int serial2002_encoder_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct serial2002_private *devpriv = dev->private; int n; int chan; @@ -819,12 +701,11 @@ static int serial2002_ei_rinsn(struct comedi_device *dev, for (n = 0; n < insn->n; n++) { struct serial_data read; - poll_channel(devpriv->tty, chan); + serial2002_poll_channel(devpriv->tty, chan); while (1) { - read = serial_read(devpriv->tty, 1000); - if (read.kind != is_channel || read.index == chan) { + read = serial2002_read(devpriv->tty, 1000); + if (read.kind != is_channel || read.index == chan) break; - } } data[n] = read.value; } @@ -834,97 +715,92 @@ static int serial2002_ei_rinsn(struct comedi_device *dev, static int serial2002_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + struct serial2002_private *devpriv; struct comedi_subdevice *s; + int ret; - printk("comedi%d: serial2002: ", dev->minor); - dev->board_name = thisboard->name; - if (alloc_private(dev, sizeof(struct serial2002_private)) < 0) { + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - } - dev->open = serial_2002_open; - dev->close = serial_2002_close; + devpriv->port = it->options[0]; devpriv->speed = it->options[1]; - printk("/dev/ttyS%d @ %d\n", devpriv->port, devpriv->speed); - if (alloc_subdevices(dev, 5) < 0) - return -ENOMEM; + ret = comedi_alloc_subdevices(dev, 5); + if (ret) + return ret; /* digital input subdevice */ - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_read = &serial2002_di_rinsn; + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 0; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_read = serial2002_di_insn_read; /* digital output subdevice */ - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_write = &serial2002_do_winsn; + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 0; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_write = serial2002_do_insn_write; /* analog input subdevice */ - s = dev->subdevices + 2; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = 0; - s->insn_read = &serial2002_ai_rinsn; + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 0; + s->maxdata = 1; + s->range_table = NULL; + s->insn_read = serial2002_ai_insn_read; /* analog output subdevice */ - s = dev->subdevices + 3; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = 0; - s->insn_write = &serial2002_ao_winsn; - s->insn_read = &serial2002_ao_rinsn; + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 0; + s->maxdata = 1; + s->range_table = NULL; + s->insn_write = serial2002_ao_insn_write; + s->insn_read = serial2002_ao_insn_read; /* encoder input subdevice */ - s = dev->subdevices + 4; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE | SDF_LSAMPL; - s->n_chan = 0; - s->maxdata = 1; - s->range_table = 0; - s->insn_read = &serial2002_ei_rinsn; - - return 1; + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE | SDF_LSAMPL; + s->n_chan = 0; + s->maxdata = 1; + s->range_table = NULL; + s->insn_read = serial2002_encoder_insn_read; + + dev->open = serial2002_open; + dev->close = serial2002_close; + + return 0; } -static int serial2002_detach(struct comedi_device *dev) +static void serial2002_detach(struct comedi_device *dev) { struct comedi_subdevice *s; int i; - printk("comedi%d: serial2002: remove\n", dev->minor); - for (i = 0; i < 5; i++) { + for (i = 0; i < dev->n_subdevices; i++) { s = &dev->subdevices[i]; kfree(s->maxdata_list); kfree(s->range_table_list); } - return 0; -} - -static int __init driver_serial2002_init_module(void) -{ - return comedi_driver_register(&driver_serial2002); } -static void __exit driver_serial2002_cleanup_module(void) -{ - comedi_driver_unregister(&driver_serial2002); -} - -module_init(driver_serial2002_init_module); -module_exit(driver_serial2002_cleanup_module); +static struct comedi_driver serial2002_driver = { + .driver_name = "serial2002", + .module = THIS_MODULE, + .attach = serial2002_attach, + .detach = serial2002_detach, +}; +module_comedi_driver(serial2002_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index ed69008f0d3..3bfa221faf4 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -14,11 +14,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: skel @@ -72,9 +67,12 @@ Configuration Options: * options that are used with comedi_config. */ +#include <linux/module.h> +#include <linux/pci.h> + #include "../comedidev.h" -#include <linux/pci.h> /* for PCI devices */ +#include "comedi_fc.h" /* Imaginary registers for the imaginary board */ @@ -88,6 +86,11 @@ Configuration Options: * 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; @@ -96,38 +99,19 @@ struct skel_board { }; static const struct skel_board skel_boards[] = { - { - .name = "skel-100", - .ai_chans = 16, - .ai_bits = 12, - .have_dio = 1, - }, - { - .name = "skel-200", - .ai_chans = 8, - .ai_bits = 16, - .have_dio = 0, - }, -}; - -/* This is used by modprobe to translate PCI IDs to drivers. Should - * only be used for PCI and ISA-PnP devices */ -/* Please add your PCI vendor ID to comedidev.h, and it will be forwarded - * upstream. */ -#define PCI_VENDOR_ID_SKEL 0xdafe -static DEFINE_PCI_DEVICE_TABLE(skel_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_SKEL, 0x0100) }, - { PCI_DEVICE(PCI_VENDOR_ID_SKEL, 0x0200) }, - { 0 } + [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, + }, }; -MODULE_DEVICE_TABLE(pci, skel_pci_table); - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct skel_board *)dev->board_ptr) - /* 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. @@ -136,170 +120,48 @@ struct skel_private { int data; - /* would be useful for a PCI device */ - struct pci_dev *pci_dev; - /* Used for AO readback */ unsigned int ao_readback[2]; }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct skel_private *)dev->private) - -/* - * 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 int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int skel_detach(struct comedi_device *dev); -static struct comedi_driver driver_skel = { - .driver_name = "dummy", - .module = THIS_MODULE, - .attach = skel_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), -}; - -static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int skel_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int skel_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int skel_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd); -static int skel_ns_to_timer(unsigned int *ns, int round); - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it) +/* 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, int round) { - struct comedi_subdevice *s; - - pr_info("comedi%d: skel: ", dev->minor); - -/* - * 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); */ - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct skel_private)) < 0) - return -ENOMEM; - -/* - * Allocate the subdevice structures. alloc_subdevice() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_subdevices(dev, 3) < 0) - return -ENOMEM; - - 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; - } - - pr_info("attached\n"); + /* 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 0; + return *ns; } /* - * _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. + * 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_detach(struct comedi_device *dev) +static int skel_ai_eoc(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned long context) { - pr_info("comedi%d: skel: remove\n", dev->minor); + unsigned int status; - return 0; + /* status = inb(dev->iobase + SKEL_STATUS); */ + status = 1; + if (status) + return 0; + return -EBUSY; } /* @@ -309,9 +171,10 @@ static int skel_detach(struct comedi_device *dev) static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int n, i; + const struct skel_board *thisboard = comedi_board(dev); + int n; unsigned int d; - unsigned int status; + int ret; /* a typical programming sequence */ @@ -325,20 +188,10 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, /* trigger conversion */ /* outw(0,dev->iobase + SKEL_CONVERT); */ -#define TIMEOUT 100 /* wait for conversion to end */ - for (i = 0; i < TIMEOUT; i++) { - status = 1; - /* status = inb(dev->iobase + SKEL_STATUS); */ - if (status) - break; - } - if (i == TIMEOUT) { - /* printk() should be used instead of printk() - * whenever the code can be called from real-time. */ - pr_info("timeout\n"); - return -ETIMEDOUT; - } + ret = comedi_timeout(dev, s, insn, skel_ai_eoc, 0); + if (ret) + return ret; /* read data */ /* d = inw(dev->iobase + SKEL_AI_DATA); */ @@ -354,125 +207,78 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 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) + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* 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. */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + unsigned int arg; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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 2: make sure trigger sources are unique and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + 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: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } #define MAX_SPEED 10000 /* in nanoseconds */ #define MIN_SPEED 1000000000 /* in nanoseconds */ if (cmd->scan_begin_src == TRIG_TIMER) { - if (cmd->scan_begin_arg < MAX_SPEED) { - cmd->scan_begin_arg = MAX_SPEED; - err++; - } - if (cmd->scan_begin_arg > MIN_SPEED) { - cmd->scan_begin_arg = MIN_SPEED; - err++; - } + 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 */ - if (cmd->scan_begin_arg > 9) { - cmd->scan_begin_arg = 9; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); } + if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < MAX_SPEED) { - cmd->convert_arg = MAX_SPEED; - err++; - } - if (cmd->convert_arg > MIN_SPEED) { - cmd->convert_arg = MIN_SPEED; - err++; - } + 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 */ - if (cmd->convert_arg > 9) { - cmd->convert_arg = 9; - err++; - } + err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9); } - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } - if (cmd->stop_src == TRIG_COUNT) { - if (cmd->stop_arg > 0x00ffffff) { - cmd->stop_arg = 0x00ffffff; - err++; - } - } else { - /* TRIG_NONE */ - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } - } + 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; @@ -480,24 +286,19 @@ static int skel_ai_cmdtest(struct comedi_device *dev, /* step 4: fix up any arguments */ if (cmd->scan_begin_src == TRIG_TIMER) { - tmp = cmd->scan_begin_arg; - skel_ns_to_timer(&cmd->scan_begin_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->scan_begin_arg) - err++; + arg = cmd->scan_begin_arg; + skel_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg); } if (cmd->convert_src == TRIG_TIMER) { - tmp = cmd->convert_arg; - skel_ns_to_timer(&cmd->convert_arg, - cmd->flags & TRIG_ROUND_MASK); - if (tmp != cmd->convert_arg) - err++; - if (cmd->scan_begin_src == TRIG_TIMER && - cmd->scan_begin_arg < - cmd->convert_arg * cmd->scan_end_arg) { - cmd->scan_begin_arg = - cmd->convert_arg * cmd->scan_end_arg; - err++; + arg = cmd->convert_arg; + skel_ns_to_timer(&arg, cmd->flags & TRIG_ROUND_MASK); + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg); + + if (cmd->scan_begin_src == TRIG_TIMER) { + arg = cmd->convert_arg * cmd->scan_end_arg; + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + arg); } } @@ -507,30 +308,13 @@ static int skel_ai_cmdtest(struct comedi_device *dev, return 0; } -/* 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, int round) -{ - /* 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; -} - 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); - pr_info("skel_ao_winsn\n"); /* 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++) { @@ -548,6 +332,7 @@ static int skel_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 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); @@ -557,119 +342,386 @@ static int skel_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* DIO devices are slightly special. Although it is possible to +/* + * 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 */ + * 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) + struct comedi_insn *insn, + unsigned int *data) { - if (insn->n != 2) - return -EINVAL; - - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; + /* + * 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); */ + /* 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; */ + /* + * On return, data[1] contains the value of the digital + * input and output lines. + */ + /* data[1] = inw(dev->iobase + SKEL_DIO); */ - return 2; + /* + * 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) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + int ret; - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << chan; - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << chan); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } - /* outw(s->io_bits,dev->iobase + SKEL_DIO_CONFIG); */ + /* + * 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; } -#ifdef CONFIG_COMEDI_PCI -static int __devinit driver_skel_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +/* + * Handle common part of skel_attach() and skel_auto_attach(). + */ +static int skel_common_attach(struct comedi_device *dev) { - return comedi_pci_auto_config(dev, driver_skel.driver_name); + 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; } -static void __devexit driver_skel_pci_remove(struct pci_dev *dev) +/* + * _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) { - comedi_pci_auto_unconfig(dev); -} + const struct skel_board *thisboard; + struct skel_private *devpriv; -static struct pci_driver driver_skel_pci_driver = { - .id_table = skel_pci_table, - .probe = &driver_skel_pci_probe, - .remove = __devexit_p(&driver_skel_pci_remove) -}; +/* + * 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); */ -static int __init driver_skel_init_module(void) -{ - int retval; + 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); + * } + */ - retval = comedi_driver_register(&driver_skel); - if (retval < 0) - return retval; +/* + * 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[]. + */ - driver_skel_pci_driver.name = (char *)driver_skel.driver_name; - return pci_register_driver(&driver_skel_pci_driver); + /* + * 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); } -static void __exit driver_skel_cleanup_module(void) +/* + * _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) { - pci_unregister_driver(&driver_skel_pci_driver); - comedi_driver_unregister(&driver_skel); + 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); } -module_init(driver_skel_init_module); -module_exit(driver_skel_cleanup_module); -#else -static int __init driver_skel_init_module(void) +/* + * _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) { - return comedi_driver_register(&driver_skel); + 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); + } } -static void __exit driver_skel_cleanup_module(void) +/* + * 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) { - comedi_driver_unregister(&driver_skel); + return comedi_pci_auto_config(dev, &skel_driver, id->driver_data); } -module_init(driver_skel_init_module); -module_exit(driver_skel_cleanup_module); +/* + * 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"); diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index 526de2efa12..848c3080158 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -15,11 +15,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: ssv_dnp @@ -31,6 +26,7 @@ Status: unknown /* include files ----------------------------------------------------------- */ +#include <linux/module.h> #include "../comedidev.h" /* Some global definitions: the registers of the DNP ----------------------- */ @@ -50,113 +46,100 @@ Status: unknown #define PCMR 0xa3 /* Port C Mode Register */ #define PCDR 0xa7 /* Port C Data Register */ -/* This data structure holds information about the supported boards -------- */ - -struct dnp_board { - const char *name; - int ai_chans; - int ai_bits; - int have_dio; -}; - -/* We only support one DNP 'board' variant at the moment */ -static const struct dnp_board dnp_boards[] = { +static int dnp_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - .name = "dnp-1486", - .ai_chans = 16, - .ai_bits = 12, - .have_dio = 1, - }, -}; - -/* Useful for shorthand access to the particular board structure ----------- */ -#define thisboard ((const struct dnp_board *)dev->board_ptr) + unsigned int mask; + unsigned int val; -/* This structure is for data unique to the DNP driver --------------------- */ -struct dnp_private_data { + /* + * Ports A and B are straight forward: each bit corresponds to an + * output pin with the same order. Port C is different: bits 0...3 + * correspond to bits 4...7 of the output register (PCDR). + */ -}; - -/* Shorthand macro for faster access to the private data ------------------- */ -#define devpriv ((dnp_private *)dev->private) + mask = comedi_dio_update_state(s, data); + if (mask) { + outb(PADR, CSCIR); + outb(s->state & 0xff, CSCDR); -/* ------------------------------------------------------------------------- */ -/* 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. */ -/* */ -/* In the following section we define the API of this driver. */ -/* ------------------------------------------------------------------------- */ + outb(PBDR, CSCIR); + outb((s->state >> 8) & 0xff, CSCDR); -static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it); -static int dnp_detach(struct comedi_device *dev); + outb(PCDR, CSCIR); + val = inb(CSCDR) & 0x0f; + outb(((s->state >> 12) & 0xf0) | val, CSCDR); + } -static struct comedi_driver driver_dnp = { - .driver_name = "ssv_dnp", - .module = THIS_MODULE, - .attach = dnp_attach, - .detach = dnp_detach, - .board_name = &dnp_boards[0].name, - /* only necessary for non-PnP devs */ - .offset = sizeof(struct dnp_board), /* like ISA-PnP, PCI or PCMCIA */ - .num_names = ARRAY_SIZE(dnp_boards), -}; + outb(PADR, CSCIR); + val = inb(CSCDR); + outb(PBDR, CSCIR); + val |= (inb(CSCDR) << 8); + outb(PCDR, CSCIR); + val |= ((inb(CSCDR) & 0xf0) << 12); -static int __init driver_dnp_init_module(void) -{ - return comedi_driver_register(&driver_dnp); -} + data[1] = val; -static void __exit driver_dnp_cleanup_module(void) -{ - comedi_driver_unregister(&driver_dnp); + return insn->n; } -module_init(driver_dnp_init_module); -module_exit(driver_dnp_cleanup_module); - -static int dnp_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - static int dnp_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* ------------------------------------------------------------------------- */ -/* Attach is called by comedi core to configure the driver for a particular */ -/* board. If you specified a board_name array in the driver structure, */ -/* dev->board_ptr contains that address. */ -/* ------------------------------------------------------------------------- */ - -static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) + struct comedi_insn *insn, + unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int mask; + unsigned int val; + int ret; - struct comedi_subdevice *s; + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - printk(KERN_INFO "comedi%d: dnp: ", dev->minor); + if (chan < 8) { /* Port A */ + mask = 1 << chan; + outb(PAMR, CSCIR); + } else if (chan < 16) { /* Port B */ + mask = 1 << (chan - 8); + outb(PBMR, CSCIR); + } else { /* Port C */ + /* + * We have to pay attention with port C. + * This is the meaning of PCMR: + * Bit in PCMR: 7 6 5 4 3 2 1 0 + * Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch + * + * Multiplication by 2 brings bits into correct position + * for PCMR! + */ + mask = 1 << ((chan - 16) * 2); + outb(PCMR, CSCIR); + } - /* Autoprobing: this should find out which board we have. Currently */ - /* only the 1486 board is supported and autoprobing is not */ - /* implemented :-) */ - /* dev->board_ptr = dnp_probe(dev); */ + val = inb(CSCDR); + if (data[0] == COMEDI_OUTPUT) + val |= mask; + else + val &= ~mask; + outb(val, CSCDR); - /* Initialize the name of the board. */ - /* We can use the "thisboard" macro now. */ - dev->board_name = thisboard->name; + return insn->n; - /* Allocate the private structure area. alloc_private() is a */ - /* convenient macro defined in comedidev.h. */ - if (alloc_private(dev, sizeof(struct dnp_private_data)) < 0) - return -ENOMEM; +} - /* Allocate the subdevice structures. alloc_subdevice() is a */ - /* convenient macro defined in comedidev.h. */ +static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + struct comedi_subdevice *s; + int ret; - if (alloc_subdevices(dev, 1) < 0) - return -ENOMEM; + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -166,8 +149,6 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = dnp_dio_insn_bits; s->insn_config = dnp_dio_insn_config; - printk("attached\n"); - /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always * allocated for the primary 8259, so we don't need to allocate them * ourselves. */ @@ -180,151 +161,26 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(PCMR, CSCIR); outb((inb(CSCDR) & 0xAA), CSCDR); - return 1; - + return 0; } -/* ------------------------------------------------------------------------- */ -/* detach is called to deconfigure a device. It should deallocate the */ -/* resources. This function is also called when _attach() fails, so it */ -/* should be careful not to release resources that were not necessarily */ -/* allocated by _attach(). dev->private and dev->subdevices are */ -/* deallocated automatically by the core. */ -/* ------------------------------------------------------------------------- */ - -static int dnp_detach(struct comedi_device *dev) +static void dnp_detach(struct comedi_device *dev) { - - /* configure all ports as input (default) */ outb(PAMR, CSCIR); outb(0x00, CSCDR); outb(PBMR, CSCIR); outb(0x00, CSCDR); outb(PCMR, CSCIR); outb((inb(CSCDR) & 0xAA), CSCDR); - - /* announce that we are finished */ - printk(KERN_INFO "comedi%d: dnp: remove\n", dev->minor); - - return 0; - -} - -/* ------------------------------------------------------------------------- */ -/* The insn_bits interface allows packed reading/writing of DIO channels. */ -/* The comedi core can convert between insn_bits and insn_read/write, so you */ -/* are able to use these instructions as well. */ -/* ------------------------------------------------------------------------- */ - -static int dnp_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - if (insn->n != 2) - return -EINVAL; /* insn uses data[0] and data[1] */ - - /* The insn data is a mask in data[0] and the new data in data[1], */ - /* each channel cooresponding to a bit. */ - - /* Ports A and B are straight forward: each bit corresponds to an */ - /* output pin with the same order. Port C is different: bits 0...3 */ - /* correspond to bits 4...7 of the output register (PCDR). */ - - if (data[0]) { - - outb(PADR, CSCIR); - outb((inb(CSCDR) - & ~(u8) (data[0] & 0x0000FF)) - | (u8) (data[1] & 0x0000FF), CSCDR); - - outb(PBDR, CSCIR); - outb((inb(CSCDR) - & ~(u8) ((data[0] & 0x00FF00) >> 8)) - | (u8) ((data[1] & 0x00FF00) >> 8), CSCDR); - - outb(PCDR, CSCIR); - outb((inb(CSCDR) - & ~(u8) ((data[0] & 0x0F0000) >> 12)) - | (u8) ((data[1] & 0x0F0000) >> 12), CSCDR); - } - - /* on return, data[1] contains the value of the digital input lines. */ - outb(PADR, CSCIR); - data[0] = inb(CSCDR); - outb(PBDR, CSCIR); - data[0] += inb(CSCDR) << 8; - outb(PCDR, CSCIR); - data[0] += ((inb(CSCDR) & 0xF0) << 12); - - return 2; - } -/* ------------------------------------------------------------------------- */ -/* Configure the direction of the bidirectional digital i/o pins. chanspec */ -/* contains the channel to be changed and data[0] contains either */ -/* COMEDI_INPUT or COMEDI_OUTPUT. */ -/* ------------------------------------------------------------------------- */ - -static int dnp_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - - u8 register_buffer; - - /* reduces chanspec to lower 16 bits */ - int chan = CR_CHAN(insn->chanspec); - - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - case INSN_CONFIG_DIO_INPUT: - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (inb(CSCDR) & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - return insn->n; - break; - default: - return -EINVAL; - break; - } - /* Test: which port does the channel belong to? */ - - /* We have to pay attention with port C: this is the meaning of PCMR: */ - /* Bit in PCMR: 7 6 5 4 3 2 1 0 */ - /* Corresponding port C pin: d 3 d 2 d 1 d 0 d= don't touch */ - - if ((chan >= 0) && (chan <= 7)) { - /* this is port A */ - outb(PAMR, CSCIR); - } else if ((chan >= 8) && (chan <= 15)) { - /* this is port B */ - chan -= 8; - outb(PBMR, CSCIR); - } else if ((chan >= 16) && (chan <= 19)) { - /* this is port C; multiplication with 2 brings bits into */ - /* correct position for PCMR! */ - chan -= 16; - chan *= 2; - outb(PCMR, CSCIR); - } else { - return -EINVAL; - } - - /* read 'old' direction of the port and set bits (out=1, in=0) */ - register_buffer = inb(CSCDR); - if (data[0] == COMEDI_OUTPUT) - register_buffer |= (1 << chan); - else - register_buffer &= ~(1 << chan); - - outb(register_buffer, CSCDR); - - return 1; - -} +static struct comedi_driver dnp_driver = { + .driver_name = "dnp-1486", + .module = THIS_MODULE, + .attach = dnp_attach, + .detach = dnp_detach, +}; +module_comedi_driver(dnp_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/unioxx5.c b/drivers/staging/comedi/drivers/unioxx5.c index 598884ec3ed..adf7cb7086c 100644 --- a/drivers/staging/comedi/drivers/unioxx5.c +++ b/drivers/staging/comedi/drivers/unioxx5.c @@ -18,10 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software * - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * - * * ***************************************************************************/ /* @@ -42,9 +38,10 @@ Devices: [Fastwel] UNIOxx-5 (unioxx5), */ + +#include <linux/module.h> +#include <linux/delay.h> #include "../comedidev.h" -#include <linux/ioport.h> -#include <linux/slab.h> #define DRIVER_NAME "unioxx5" #define UNIOXX5_SIZE 0x10 @@ -75,102 +72,206 @@ Devices: [Fastwel] UNIOxx-5 (unioxx5), /* 'private' structure for each subdevice */ struct unioxx5_subd_priv { int usp_iobase; - unsigned char usp_module_type[12]; /* 12 modules. each can be 70L or 73L */ - unsigned char usp_extra_data[12][4]; /* for saving previous written value for analog modules */ + /* 12 modules. each can be 70L or 73L */ + unsigned char usp_module_type[12]; + /* for saving previous written value for analog modules */ + unsigned char usp_extra_data[12][4]; unsigned char usp_prev_wr_val[3]; /* previous written value */ unsigned char usp_prev_cn_val[3]; /* previous channel value */ }; -static int unioxx5_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static int unioxx5_subdev_write(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data); -static int unioxx5_subdev_read(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data); -static int unioxx5_insn_config(struct comedi_device *dev, - struct comedi_subdevice *subdev, - struct comedi_insn *insn, unsigned int *data); -static int unioxx5_detach(struct comedi_device *dev); -static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, - int subdev_iobase, int minor); -static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor); -static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor); -/* static void __unioxx5_digital_config(struct unioxx5_subd_priv* usp, int mode); */ -static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor); -static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor); -static int __unioxx5_define_chan_offset(int chan_num); -static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel); +static int __unioxx5_define_chan_offset(int chan_num) +{ -static struct comedi_driver unioxx5_driver = { - .driver_name = DRIVER_NAME, - .module = THIS_MODULE, - .attach = unioxx5_attach, - .detach = unioxx5_detach -}; + if (chan_num < 0 || chan_num > 23) + return -1; -static int __init unioxx5_driver_init_module(void) + return (chan_num >> 3) + 1; +} + +#if 0 /* not used? */ +static void __unioxx5_digital_config(struct comedi_subdevice *s, int mode) { - return comedi_driver_register(&unioxx5_driver); + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; + int i, mask; + + mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00; + dev_dbg(csdev, "mode = %d\n", mask); + + outb(1, usp->usp_iobase + 0); + + for (i = 0; i < 3; i++) + outb(mask, usp->usp_iobase + i); + + outb(0, usp->usp_iobase + 0); } +#endif -static void __exit unioxx5_driver_cleanup_module(void) +/* configure channels for analog i/o (even to output, odd to input) */ +static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel) { - comedi_driver_unregister(&unioxx5_driver); + int chan_a, chan_b, conf, channel_offset; + + channel_offset = __unioxx5_define_chan_offset(channel); + conf = usp->usp_prev_cn_val[channel_offset - 1]; + chan_a = chan_b = 1; + + /* setting channel A and channel B mask */ + if (channel % 2 == 0) { + chan_a <<= channel & 0x07; + chan_b <<= (channel + 1) & 0x07; + } else { + chan_a <<= (channel - 1) & 0x07; + chan_b <<= channel & 0x07; + } + + conf |= chan_a; /* even channel ot output */ + conf &= ~chan_b; /* odd channel to input */ + + outb(1, usp->usp_iobase + 0); + outb(conf, usp->usp_iobase + channel_offset); + outb(0, usp->usp_iobase + 0); + + usp->usp_prev_cn_val[channel_offset - 1] = conf; } -module_init(unioxx5_driver_init_module); -module_exit(unioxx5_driver_cleanup_module); +static int __unioxx5_digital_read(struct comedi_subdevice *s, + unsigned int *data, int channel, int minor) +{ + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; + int channel_offset, mask = 1 << (channel & 0x07); -static int unioxx5_attach(struct comedi_device *dev, - struct comedi_devconfig *it) + channel_offset = __unioxx5_define_chan_offset(channel); + if (channel_offset < 0) { + dev_err(csdev, + "undefined channel %d. channel range is 0 .. 23\n", + channel); + return 0; + } + + *data = inb(usp->usp_iobase + channel_offset); + *data &= mask; + + /* correct the read value to 0 or 1 */ + if (channel_offset > 1) + channel -= 2 << channel_offset; + *data >>= channel; + return 1; +} + +static int __unioxx5_analog_read(struct comedi_subdevice *s, + unsigned int *data, int channel, int minor) { - int iobase, i, n_subd; - int id, num, ba; + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; + int module_no, read_ch; + char control; - iobase = it->options[0]; + module_no = channel / 2; + read_ch = channel % 2; /* depend on type of channel (A or B) */ - dev->board_name = DRIVER_NAME; - dev->iobase = iobase; - iobase += UNIOXX5_SUBDEV_BASE; + /* defining if given module can work on input */ + if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) { + dev_err(csdev, + "module in position %d with id 0x%02x is for output only", + module_no, usp->usp_module_type[module_no]); + return 0; + } - /* defining number of subdevices and getting they types (it must be 'g01') */ - for (i = n_subd = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) { - id = inb(ba + 0xE); - num = inb(ba + 0xF); + __unioxx5_analog_config(usp, channel); + /* sends module number to card(1 .. 12) */ + outb(module_no + 1, usp->usp_iobase + 5); + outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */ + control = inb(usp->usp_iobase); /* get control register byte */ - if (id != 'g' || num != 1) - continue; + /* waits while reading four bytes will be allowed */ + while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA)) + ; - n_subd++; + /* if four bytes readding error occurs - return 0(false) */ + if ((control & Rx4CA_ERR_MASK)) { + dev_err(csdev, "4 bytes error\n"); + return 0; } - /* unioxx5 can has from two to four subdevices */ - if (n_subd < 2) { - printk(KERN_ERR - "your card must has at least 2 'g01' subdevices\n"); - return -1; + if (read_ch) + *data = inw(usp->usp_iobase + 6); /* channel B */ + else + *data = inw(usp->usp_iobase + 4); /* channel A */ + + return 1; +} + +static int __unioxx5_digital_write(struct comedi_subdevice *s, + unsigned int *data, int channel, int minor) +{ + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; + int channel_offset, val; + int mask = 1 << (channel & 0x07); + + channel_offset = __unioxx5_define_chan_offset(channel); + if (channel_offset < 0) { + dev_err(csdev, + "undefined channel %d. channel range is 0 .. 23\n", + channel); + return 0; } - if (alloc_subdevices(dev, n_subd) < 0) { - printk(KERN_ERR "out of memory\n"); - return -ENOMEM; + /* getting previous written value */ + val = usp->usp_prev_wr_val[channel_offset - 1]; + + if (*data) + val |= mask; + else + val &= ~mask; + + outb(val, usp->usp_iobase + channel_offset); + /* saving new written value */ + usp->usp_prev_wr_val[channel_offset - 1] = val; + + return 1; +} + +static int __unioxx5_analog_write(struct comedi_subdevice *s, + unsigned int *data, int channel, int minor) +{ + struct unioxx5_subd_priv *usp = s->private; + struct device *csdev = s->device->class_dev; + int module, i; + + module = channel / 2; /* definig module number(0 .. 11) */ + i = (channel % 2) << 1; /* depends on type of channel (A or B) */ + + /* defining if given module can work on output */ + if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) { + dev_err(csdev, + "module in position %d with id 0x%0x is for input only!\n", + module, usp->usp_module_type[module]); + return 0; } - /* initializing each of for same subdevices */ - for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) { - if (__unioxx5_subdev_init(&dev->subdevices[i], iobase, - dev->minor) < 0) - return -1; + __unioxx5_analog_config(usp, channel); + /* saving minor byte */ + usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF); + /* saving major byte */ + usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8); + + /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */ + /* sending module number to card(1 .. 12) */ + outb(module + 1, usp->usp_iobase + 5); + outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */ + + /* sending for bytes to module(one byte per cycle iteration) */ + for (i = 0; i < 4; i++) { + while (!((inb(usp->usp_iobase + 0)) & TxBE)) + ; /* waits while writting will be allowed */ + outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6); } - printk("attached\n"); - return 0; + return 1; } static int unioxx5_subdev_read(struct comedi_device *dev, @@ -181,13 +282,14 @@ static int unioxx5_subdev_read(struct comedi_device *dev, int channel, type; channel = CR_CHAN(insn->chanspec); - type = usp->usp_module_type[channel / 2]; /* defining module type(analog or digital) */ + /* defining module type(analog or digital) */ + type = usp->usp_module_type[channel / 2]; if (type == MODULE_DIGITAL) { - if (!__unioxx5_digital_read(usp, data, channel, dev->minor)) + if (!__unioxx5_digital_read(subdev, data, channel, dev->minor)) return -1; } else { - if (!__unioxx5_analog_read(usp, data, channel, dev->minor)) + if (!__unioxx5_analog_read(subdev, data, channel, dev->minor)) return -1; } @@ -202,13 +304,14 @@ static int unioxx5_subdev_write(struct comedi_device *dev, int channel, type; channel = CR_CHAN(insn->chanspec); - type = usp->usp_module_type[channel / 2]; /* defining module type(analog or digital) */ + /* defining module type(analog or digital) */ + type = usp->usp_module_type[channel / 2]; if (type == MODULE_DIGITAL) { - if (!__unioxx5_digital_write(usp, data, channel, dev->minor)) + if (!__unioxx5_digital_write(subdev, data, channel, dev->minor)) return -1; } else { - if (!__unioxx5_analog_write(usp, data, channel, dev->minor)) + if (!__unioxx5_analog_write(subdev, data, channel, dev->minor)) return -1; } @@ -227,17 +330,16 @@ static int unioxx5_insn_config(struct comedi_device *dev, type = usp->usp_module_type[channel / 2]; if (type != MODULE_DIGITAL) { - printk(KERN_ERR - "comedi%d: channel configuration accessible only for digital modules\n", - dev->minor); + dev_err(dev->class_dev, + "channel configuration accessible only for digital modules\n"); return -1; } channel_offset = __unioxx5_define_chan_offset(channel); if (channel_offset < 0) { - printk(KERN_ERR - "comedi%d: undefined channel %d. channel range is 0 .. 23\n", - dev->minor, channel); + dev_err(dev->class_dev, + "undefined channel %d. channel range is 0 .. 23\n", + channel); return -1; } @@ -252,7 +354,7 @@ static int unioxx5_insn_config(struct comedi_device *dev, flags |= mask; break; default: - printk(KERN_ERR "comedi%d: unknown flag\n", dev->minor); + dev_err(dev->class_dev, "unknown flag\n"); return -1; } @@ -261,64 +363,48 @@ static int unioxx5_insn_config(struct comedi_device *dev, * change channel type on input or output) * \* */ outb(1, usp->usp_iobase + 0); - outb(flags, usp->usp_iobase + channel_offset); /* changes type of _one_ channel */ - outb(0, usp->usp_iobase + 0); /* sets channels bank to 0(allows directly input/output) */ - usp->usp_prev_cn_val[channel_offset - 1] = flags; /* saves written value */ - - return 0; -} - -static int unioxx5_detach(struct comedi_device *dev) -{ - int i; - struct comedi_subdevice *subdev; - struct unioxx5_subd_priv *usp; - - for (i = 0; i < dev->n_subdevices; i++) { - subdev = &dev->subdevices[i]; - usp = subdev->private; - release_region(usp->usp_iobase, UNIOXX5_SIZE); - kfree(subdev->private); - } + /* changes type of _one_ channel */ + outb(flags, usp->usp_iobase + channel_offset); + /* sets channels bank to 0(allows directly input/output) */ + outb(0, usp->usp_iobase + 0); + /* saves written value */ + usp->usp_prev_cn_val[channel_offset - 1] = flags; return 0; } /* initializing subdevice with given address */ -static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, - int subdev_iobase, int minor) +static int __unioxx5_subdev_init(struct comedi_device *dev, + struct comedi_subdevice *s, + int iobase) { struct unioxx5_subd_priv *usp; int i, to, ndef_flag = 0; + int ret; - if (!request_region(subdev_iobase, UNIOXX5_SIZE, DRIVER_NAME)) { - printk(KERN_ERR "comedi%d: I/O port conflict\n", minor); - return -EIO; - } - - usp = kzalloc(sizeof(*usp), GFP_KERNEL); - - if (usp == NULL) { - printk(KERN_ERR "comedi%d: erorr! --> out of memory!\n", minor); - return -1; - } + usp = comedi_alloc_spriv(s, sizeof(*usp)); + if (!usp) + return -ENOMEM; - usp->usp_iobase = subdev_iobase; - printk("comedi%d: |", minor); + ret = __comedi_request_region(dev, iobase, UNIOXX5_SIZE); + if (ret) + return ret; + usp->usp_iobase = iobase; /* defining modules types */ for (i = 0; i < 12; i++) { to = 10000; __unioxx5_analog_config(usp, i * 2); - outb(i + 1, subdev_iobase + 5); /* sends channel number to card */ - outb('H', subdev_iobase + 6); /* requests EEPROM world */ - while (!(inb(subdev_iobase + 0) & TxBE)) + /* sends channel number to card */ + outb(i + 1, iobase + 5); + outb('H', iobase + 6); /* requests EEPROM world */ + while (!(inb(iobase + 0) & TxBE)) ; /* waits while writting will be allowed */ - outb(0, subdev_iobase + 6); + outb(0, iobase + 6); /* waits while reading of two bytes will be allowed */ - while (!(inb(subdev_iobase + 0) & Rx2CA)) { + while (!(inb(iobase + 0) & Rx2CA)) { if (--to <= 0) { ndef_flag = 1; break; @@ -329,217 +415,93 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev, usp->usp_module_type[i] = 0; ndef_flag = 0; } else - usp->usp_module_type[i] = inb(subdev_iobase + 6); + usp->usp_module_type[i] = inb(iobase + 6); - printk(" [%d] 0x%02x |", i, usp->usp_module_type[i]); udelay(1); } - printk("\n"); - /* initial subdevice for digital or analog i/o */ - subdev->type = COMEDI_SUBD_DIO; - subdev->private = usp; - subdev->subdev_flags = SDF_READABLE | SDF_WRITABLE; - subdev->n_chan = UNIOXX5_NUM_OF_CHANS; - subdev->maxdata = 0xFFF; - subdev->range_table = &range_digital; - subdev->insn_read = unioxx5_subdev_read; - subdev->insn_write = unioxx5_subdev_write; - subdev->insn_config = unioxx5_insn_config; /* for digital modules only!!! */ - - printk("subdevice configured\n"); + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = UNIOXX5_NUM_OF_CHANS; + s->maxdata = 0xFFF; + s->range_table = &range_digital; + s->insn_read = unioxx5_subdev_read; + s->insn_write = unioxx5_subdev_write; + /* for digital modules only!!! */ + s->insn_config = unioxx5_insn_config; return 0; } -static int __unioxx5_digital_write(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor) -{ - int channel_offset, val; - int mask = 1 << (channel & 0x07); - - channel_offset = __unioxx5_define_chan_offset(channel); - if (channel_offset < 0) { - printk(KERN_ERR - "comedi%d: undefined channel %d. channel range is 0 .. 23\n", - minor, channel); - return 0; - } - - val = usp->usp_prev_wr_val[channel_offset - 1]; /* getting previous written value */ - - if (*data) - val |= mask; - else - val &= ~mask; - - outb(val, usp->usp_iobase + channel_offset); - usp->usp_prev_wr_val[channel_offset - 1] = val; /* saving new written value */ - - return 1; -} - -/* function for digital reading */ -static int __unioxx5_digital_read(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor) -{ - int channel_offset, mask = 1 << (channel & 0x07); - - channel_offset = __unioxx5_define_chan_offset(channel); - if (channel_offset < 0) { - printk(KERN_ERR - "comedi%d: undefined channel %d. channel range is 0 .. 23\n", - minor, channel); - return 0; - } - - *data = inb(usp->usp_iobase + channel_offset); - *data &= mask; - - if (channel_offset > 1) - channel -= 2 << channel_offset; /* this operation is created for correct readed value to 0 or 1 */ - - *data >>= channel; - return 1; -} - -#if 0 /* not used? */ -static void __unioxx5_digital_config(struct unioxx5_subd_priv *usp, int mode) -{ - int i, mask; - - mask = (mode == ALL_2_OUTPUT) ? 0xFF : 0x00; - printk("COMEDI: mode = %d\n", mask); - - outb(1, usp->usp_iobase + 0); - - for (i = 0; i < 3; i++) - outb(mask, usp->usp_iobase + i); - - outb(0, usp->usp_iobase + 0); -} -#endif - -static int __unioxx5_analog_write(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor) +static int unioxx5_attach(struct comedi_device *dev, + struct comedi_devconfig *it) { - int module, i; + struct comedi_subdevice *s; + int iobase, i, n_subd; + int id, num, ba; + int ret; - module = channel / 2; /* definig module number(0 .. 11) */ - i = (channel % 2) << 1; /* depends on type of channel (A or B) */ + iobase = it->options[0]; - /* defining if given module can work on output */ - if (!(usp->usp_module_type[module] & MODULE_OUTPUT_MASK)) { - printk(KERN_ERR - "comedi%d: module in position %d with id 0x%0x is for input only!\n", - minor, module, usp->usp_module_type[module]); - return 0; - } + dev->iobase = iobase; + iobase += UNIOXX5_SUBDEV_BASE; + n_subd = 0; - __unioxx5_analog_config(usp, channel); - /* saving minor byte */ - usp->usp_extra_data[module][i++] = (unsigned char)(*data & 0x00FF); - /* saving major byte */ - usp->usp_extra_data[module][i] = (unsigned char)((*data & 0xFF00) >> 8); + /* getting number of subdevices with types 'g01' */ + for (i = 0, ba = iobase; i < 4; i++, ba += UNIOXX5_SUBDEV_ODDS) { + id = inb(ba + 0xE); + num = inb(ba + 0xF); - /* while(!((inb(usp->usp_iobase + 0)) & TxBE)); */ - outb(module + 1, usp->usp_iobase + 5); /* sending module number to card(1 .. 12) */ - outb('W', usp->usp_iobase + 6); /* sends (W)rite command to module */ + if (id != 'g' || num != 1) + continue; - /* sending for bytes to module(one byte per cycle iteration) */ - for (i = 0; i < 4; i++) { - while (!((inb(usp->usp_iobase + 0)) & TxBE)) - ; /* waits while writting will be allowed */ - outb(usp->usp_extra_data[module][i], usp->usp_iobase + 6); + n_subd++; } - return 1; -} - -static int __unioxx5_analog_read(struct unioxx5_subd_priv *usp, - unsigned int *data, int channel, int minor) -{ - int module_no, read_ch; - char control; - - module_no = channel / 2; - read_ch = channel % 2; /* depend on type of channel (A or B) */ - - /* defining if given module can work on input */ - if (usp->usp_module_type[module_no] & MODULE_OUTPUT_MASK) { - printk(KERN_ERR - "comedi%d: module in position %d with id 0x%02x is for output only", - minor, module_no, usp->usp_module_type[module_no]); - return 0; + /* unioxx5 can has from two to four subdevices */ + if (n_subd < 2) { + dev_err(dev->class_dev, + "your card must has at least 2 'g01' subdevices\n"); + return -1; } - __unioxx5_analog_config(usp, channel); - outb(module_no + 1, usp->usp_iobase + 5); /* sends module number to card(1 .. 12) */ - outb('V', usp->usp_iobase + 6); /* sends to module (V)erify command */ - control = inb(usp->usp_iobase); /* get control register byte */ + ret = comedi_alloc_subdevices(dev, n_subd); + if (ret) + return ret; - /* waits while reading four bytes will be allowed */ - while (!((control = inb(usp->usp_iobase + 0)) & Rx4CA)) - ; - - /* if four bytes readding error occurs - return 0(false) */ - if ((control & Rx4CA_ERR_MASK)) { - printk("COMEDI: 4 bytes error\n"); - return 0; + /* initializing each of for same subdevices */ + for (i = 0; i < n_subd; i++, iobase += UNIOXX5_SUBDEV_ODDS) { + s = &dev->subdevices[i]; + ret = __unioxx5_subdev_init(dev, s, iobase); + if (ret) + return ret; } - if (read_ch) - *data = inw(usp->usp_iobase + 6); /* channel B */ - else - *data = inw(usp->usp_iobase + 4); /* channel A */ - - return 1; + return 0; } -/* configure channels for analog i/o (even to output, odd to input) */ -static void __unioxx5_analog_config(struct unioxx5_subd_priv *usp, int channel) +static void unioxx5_detach(struct comedi_device *dev) { - int chan_a, chan_b, conf, channel_offset; - - channel_offset = __unioxx5_define_chan_offset(channel); - conf = usp->usp_prev_cn_val[channel_offset - 1]; - chan_a = chan_b = 1; + struct comedi_subdevice *s; + struct unioxx5_subd_priv *spriv; + int i; - /* setting channel A and channel B mask */ - if (channel % 2 == 0) { - chan_a <<= channel & 0x07; - chan_b <<= (channel + 1) & 0x07; - } else { - chan_a <<= (channel - 1) & 0x07; - chan_b <<= channel & 0x07; + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + spriv = s->private; + if (spriv && spriv->usp_iobase) + release_region(spriv->usp_iobase, UNIOXX5_SIZE); } - - conf |= chan_a; /* even channel ot output */ - conf &= ~chan_b; /* odd channel to input */ - - outb(1, usp->usp_iobase + 0); - outb(conf, usp->usp_iobase + channel_offset); - outb(0, usp->usp_iobase + 0); - - usp->usp_prev_cn_val[channel_offset - 1] = conf; } -/* *\ - * this function defines if the given channel number * - * enters in default numeric interspace(from 0 to 23) * - * and it returns address offset for usage needed * - * channel. * -\* */ - -static int __unioxx5_define_chan_offset(int chan_num) -{ - - if (chan_num < 0 || chan_num > 23) - return -1; - - return (chan_num >> 3) + 1; -} +static struct comedi_driver unioxx5_driver = { + .driver_name = DRIVER_NAME, + .module = THIS_MODULE, + .attach = unioxx5_attach, + .detach = unioxx5_detach, +}; +module_comedi_driver(unioxx5_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 1d09bfa2edf..5f65e4213c6 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -1,6 +1,3 @@ -#define DRIVER_VERSION "v2.4" -#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com" -#define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com" /* comedi/drivers/usbdux.c Copyright (C) 2003-2007 Bernd Porr, Bernd.Porr@f2s.com @@ -14,11 +11,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: usbdux @@ -59,7 +51,7 @@ sampling rate. If you sample two channels you get 4kHz and so on. * functions firmware upload is by fxload and no longer by comedi (due to * enumeration) * 0.97: USB IDs received, adjusted table - * 0.98: SMP, locking, memroy alloc: moved all usb memory alloc + * 0.98: SMP, locking, memory alloc: moved all usb memory alloc * to the usb subsystem and moved all comedi related memory * alloc to comedi. * | kernel | registration | usbdux-usb | usbdux-comedi | comedi | @@ -76,7 +68,7 @@ sampling rate. If you sample two channels you get 4kHz and so on. * And loads of cleaning up, in particular streamlining the * bulk transfers. * 1.1: moved EP4 transfers to EP1 to make space for a PWM output on EP4 - * 1.2: added PWM suport via EP4 + * 1.2: added PWM support via EP4 * 2.0: PWM seems to be stable and is not interfering with the other functions * 2.1: changed PWM API * 2.2: added firmware kernel request to fix an udev problem @@ -86,58 +78,41 @@ sampling rate. If you sample two channels you get 4kHz and so on. * */ -/* generates loads of debug info */ -/* #define NOISY_DUX_DEBUGBUG */ - #include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/usb.h> #include <linux/fcntl.h> #include <linux/compiler.h> -#include <linux/firmware.h> #include "../comedidev.h" -#define BOARDNAME "usbdux" - -/* timeout for the USB-transfer in ms*/ -#define BULK_TIMEOUT 1000 - -/* constants for "firmware" upload and download */ -#define USBDUXSUB_FIRMWARE 0xA0 -#define VENDOR_DIR_IN 0xC0 -#define VENDOR_DIR_OUT 0x40 - -/* internal addresses of the 8051 processor */ -#define USBDUXSUB_CPUCS 0xE600 - -/* - * the minor device number, major is 180 only for debugging purposes and to - * upload special firmware (programming the eeprom etc) which is not compatible - * with the comedi framwork - */ -#define USBDUXSUB_MINOR 32 +#include "comedi_fc.h" -/* max lenghth of the transfer-buffer for software upload */ -#define TB_LEN 0x2000 +/* constants for firmware upload and download */ +#define USBDUX_FIRMWARE "usbdux_firmware.bin" +#define USBDUX_FIRMWARE_MAX_LEN 0x2000 +#define USBDUX_FIRMWARE_CMD 0xa0 +#define VENDOR_DIR_IN 0xc0 +#define VENDOR_DIR_OUT 0x40 +#define USBDUX_CPU_CS 0xe600 -/* Input endpoint number: ISO/IRQ */ -#define ISOINEP 6 +/* usbdux bulk transfer commands */ +#define USBDUX_CMD_MULT_AI 0 +#define USBDUX_CMD_AO 1 +#define USBDUX_CMD_DIO_CFG 2 +#define USBDUX_CMD_DIO_BITS 3 +#define USBDUX_CMD_SINGLE_AI 4 +#define USBDUX_CMD_TIMER_RD 5 +#define USBDUX_CMD_TIMER_WR 6 +#define USBDUX_CMD_PWM_ON 7 +#define USBDUX_CMD_PWM_OFF 8 -/* Output endpoint number: ISO/IRQ */ -#define ISOOUTEP 2 +#define USBDUX_NUM_AO_CHAN 4 -/* This EP sends DUX commands to USBDUX */ -#define COMMAND_OUT_EP 1 - -/* This EP receives the DUX commands from USBDUX */ -#define COMMAND_IN_EP 8 - -/* Output endpoint for PWM */ -#define PWM_EP 4 +/* timeout for the USB-transfer in ms */ +#define BULK_TIMEOUT 1000 /* 300Hz max frequ under PWM */ #define MIN_PWM_PERIOD ((long)(1E9/300)) @@ -145,11 +120,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. /* Default PWM frequency */ #define PWM_DEFAULT_PERIOD ((long)(1E9/100)) -/* Number of channels */ -#define NUMCHANNELS 8 - /* Size of one A/D value */ -#define SIZEADIN ((sizeof(int16_t))) +#define SIZEADIN ((sizeof(uint16_t))) /* * Size of the input-buffer IN BYTES @@ -160,11 +132,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. /* 16 bytes. */ #define SIZEINSNBUF 16 -/* Number of DA channels */ -#define NUMOUTCHANNELS 8 - /* size of one value for the D/A converter: channel and value */ -#define SIZEDAOUT ((sizeof(int8_t)+sizeof(int16_t))) +#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(uint16_t))) /* * Size of the output-buffer in bytes @@ -193,101 +162,53 @@ sampling rate. If you sample two channels you get 4kHz and so on. /* must have more buffers due to buggy USB ctr */ #define NUMOFOUTBUFFERSHIGH 10 -/* Total number of usbdux devices */ -#define NUMUSBDUX 16 - -/* Analogue in subdevice */ -#define SUBDEV_AD 0 - -/* Analogue out subdevice */ -#define SUBDEV_DA 1 - -/* Digital I/O */ -#define SUBDEV_DIO 2 - -/* counter */ -#define SUBDEV_COUNTER 3 - -/* timer aka pwm output */ -#define SUBDEV_PWM 4 - /* number of retries to get the right dux command */ #define RETRIES 10 -/**************************************************/ -/* comedi constants */ -static const struct comedi_lrange range_usbdux_ai_range = { 4, { - BIP_RANGE - (4.096), - BIP_RANGE(4.096 - / 2), - UNI_RANGE - (4.096), - UNI_RANGE(4.096 - / 2) - } +static const struct comedi_lrange range_usbdux_ai_range = { + 4, { + BIP_RANGE(4.096), + BIP_RANGE(4.096 / 2), + UNI_RANGE(4.096), + UNI_RANGE(4.096 / 2) + } }; -static const struct comedi_lrange range_usbdux_ao_range = { 2, { - BIP_RANGE - (4.096), - UNI_RANGE - (4.096), - } +static const struct comedi_lrange range_usbdux_ao_range = { + 2, { + BIP_RANGE(4.096), + UNI_RANGE(4.096) + } }; -/* - * private structure of one subdevice - */ - -/* - * This is the structure which holds all the data of - * this driver one sub device just now: A/D - */ -struct usbduxsub { - /* attached? */ - int attached; - /* is it associated with a subdevice? */ - int probed; - /* pointer to the usb-device */ - struct usb_device *usbdev; +struct usbdux_private { /* actual number of in-buffers */ - int numOfInBuffers; + int n_ai_urbs; /* actual number of out-buffers */ - int numOfOutBuffers; + int n_ao_urbs; /* ISO-transfer handling: buffers */ - struct urb **urbIn; - struct urb **urbOut; + struct urb **ai_urbs; + struct urb **ao_urbs; /* pwm-transfer handling */ - struct urb *urbPwm; + struct urb *pwm_urb; /* PWM period */ - unsigned int pwmPeriod; + unsigned int pwm_period; /* PWM internal delay for the GPIF in the FX2 */ - int8_t pwmDelay; + uint8_t pwm_delay; /* size of the PWM buffer which holds the bit pattern */ - int sizePwmBuf; + int pwm_buf_sz; /* input buffer for the ISO-transfer */ - int16_t *inBuffer; + uint16_t *in_buf; /* input buffer for single insn */ - int16_t *insnBuffer; - /* output buffer for single DA outputs */ - int16_t *outBuffer; - /* interface number */ - int ifnum; - /* interface structure in 2.6 */ - struct usb_interface *interface; - /* comedi device for the interrupt context */ - struct comedi_device *comedidev; - /* is it USB_SPEED_HIGH or not? */ - short int high_speed; - /* asynchronous command is running */ - short int ai_cmd_running; - short int ao_cmd_running; - /* pwm is running */ - short int pwm_cmd_running; - /* continous acquisition */ - short int ai_continous; - short int ao_continous; + uint16_t *insn_buf; + + unsigned int ao_readback[USBDUX_NUM_AO_CHAN]; + + unsigned int high_speed:1; + unsigned int ai_cmd_running:1; + unsigned int ao_cmd_running:1; + unsigned int pwm_cmd_running:1; + /* number of samples to acquire */ int ai_sample_count; int ao_sample_count; @@ -299,132 +220,63 @@ struct usbduxsub { unsigned int ao_counter; /* interval in frames/uframes */ unsigned int ai_interval; - /* D/A commands */ - int8_t *dac_commands; /* commands */ - int8_t *dux_commands; + uint8_t *dux_commands; struct semaphore sem; }; -/* - * The pointer to the private usb-data of the driver is also the private data - * for the comedi-device. This has to be global as the usb subsystem needs - * global variables. The other reason is that this structure must be there - * _before_ any comedi command is issued. The usb subsystem must be initialised - * before comedi can access it. - */ -static struct usbduxsub usbduxsub[NUMUSBDUX]; - -static DEFINE_SEMAPHORE(start_stop_sem); - -/* - * Stops the data acquision - * It should be safe to call this function from any context - */ -static int usbduxsub_unlink_InURBs(struct usbduxsub *usbduxsub_tmp) +static void usbdux_unlink_urbs(struct urb **urbs, int num_urbs) { - int i = 0; - int err = 0; + int i; - if (usbduxsub_tmp && usbduxsub_tmp->urbIn) { - for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) { - if (usbduxsub_tmp->urbIn[i]) { - /* We wait here until all transfers have been - * cancelled. */ - usb_kill_urb(usbduxsub_tmp->urbIn[i]); - } - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: usbdux: unlinked InURB %d, err=%d\n", - i, err); - } - } - return err; + for (i = 0; i < num_urbs; i++) + usb_kill_urb(urbs[i]); } -/* - * This will stop a running acquisition operation - * Is called from within this driver from both the - * interrupt context and from comedi - */ -static int usbdux_ai_stop(struct usbduxsub *this_usbduxsub, int do_unlink) +static void usbdux_ai_stop(struct comedi_device *dev, int do_unlink) { - int ret = 0; - - if (!this_usbduxsub) { - pr_err("comedi?: usbdux_ai_stop: this_usbduxsub=NULL!\n"); - return -EFAULT; - } - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_stop\n"); + struct usbdux_private *devpriv = dev->private; - if (do_unlink) { - /* stop aquistion */ - ret = usbduxsub_unlink_InURBs(this_usbduxsub); - } - - this_usbduxsub->ai_cmd_running = 0; + if (do_unlink && devpriv->ai_urbs) + usbdux_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs); - return ret; + devpriv->ai_cmd_running = 0; } -/* - * This will cancel a running acquisition operation. - * This is called by comedi but never from inside the driver. - */ static int usbdux_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub; - int res = 0; - - /* force unlink of all urbs */ - this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; - - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ai_cancel\n"); + struct usbdux_private *devpriv = dev->private; /* prevent other CPUs from submitting new commands just now */ - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + down(&devpriv->sem); /* unlink only if the urb really has been submitted */ - res = usbdux_ai_stop(this_usbduxsub, this_usbduxsub->ai_cmd_running); - up(&this_usbduxsub->sem); - return res; + usbdux_ai_stop(dev, devpriv->ai_cmd_running); + up(&devpriv->sem); + + return 0; } /* analogue IN - interrupt service routine */ -static void usbduxsub_ai_IsocIrq(struct urb *urb) +static void usbduxsub_ai_isoc_irq(struct urb *urb) { - int i, err, n; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - /* subdevice which is the AD converter */ - s = this_comedidev->subdevices + SUBDEV_AD; + struct comedi_device *dev = urb->context; + struct comedi_subdevice *s = dev->read_subdev; + struct usbdux_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int i, err; /* first we test if something unusual has just happened */ switch (urb->status) { case 0: /* copy the result in the transfer buffer */ - memcpy(this_usbduxsub->inBuffer, - urb->transfer_buffer, SIZEINBUF); + memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); break; case -EILSEQ: /* error in the ISOchronous data */ /* we don't copy the data into the transfer buffer */ /* and recycle the last data byte */ - dev_dbg(&urb->dev->dev, - "comedi%d: usbdux: CRC error in ISO IN stream.\n", - this_usbduxsub->comedidev->minor); - + dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); break; case -ECONNRESET: @@ -432,29 +284,27 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) case -ESHUTDOWN: case -ECONNABORTED: /* happens after an unlink command */ - if (this_usbduxsub->ai_cmd_running) { - /* we are still running a command */ - /* tell this comedi */ + if (devpriv->ai_cmd_running) { s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* stop the transfer w/o unlink */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); } return; default: /* a real error on the bus */ /* pass error to comedi if we are really running a command */ - if (this_usbduxsub->ai_cmd_running) { - dev_err(&urb->dev->dev, - "Non-zero urb status received in ai intr " - "context: %d\n", urb->status); + if (devpriv->ai_cmd_running) { + dev_err(dev->class_dev, + "Non-zero urb status received in ai intr context: %d\n", + urb->status); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* don't do an unlink here */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); } return; } @@ -463,7 +313,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) * at this point we are reasonably sure that nothing dodgy has happened * are we running a command? */ - if (unlikely((!(this_usbduxsub->ai_cmd_running)))) { + if (unlikely(!devpriv->ai_cmd_running)) { /* * not running a command, do not continue execution if no * asynchronous command is running in particular not resubmit @@ -471,144 +321,100 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) return; } - urb->dev = this_usbduxsub->usbdev; + urb->dev = comedi_to_usb_dev(dev); /* resubmit the urb */ err = usb_submit_urb(urb, GFP_ATOMIC); if (unlikely(err < 0)) { - dev_err(&urb->dev->dev, - "comedi_: urb resubmit failed in int-context! err=%d\n", - err); + dev_err(dev->class_dev, + "urb resubmit failed in int-context! err=%d\n", err); if (err == -EL2NSYNC) - dev_err(&urb->dev->dev, - "buggy USB host controller or bug in IRQ " - "handler!\n"); + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler!\n"); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* don't do an unlink here */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); return; } - this_usbduxsub->ai_counter--; - if (likely(this_usbduxsub->ai_counter > 0)) + devpriv->ai_counter--; + if (likely(devpriv->ai_counter > 0)) return; /* timer zero, transfer measurements to comedi */ - this_usbduxsub->ai_counter = this_usbduxsub->ai_timer; + devpriv->ai_counter = devpriv->ai_timer; /* test, if we transmit only a fixed number of samples */ - if (!(this_usbduxsub->ai_continous)) { + if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ - this_usbduxsub->ai_sample_count--; + devpriv->ai_sample_count--; /* all samples received? */ - if (this_usbduxsub->ai_sample_count < 0) { + if (devpriv->ai_sample_count < 0) { /* prevent a resubmit next time */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); /* say comedi that the acquistion is over */ s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); return; } } /* get the data from the USB bus and hand it over to comedi */ - n = s->async->cmd.chanlist_len; - for (i = 0; i < n; i++) { + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int range = CR_RANGE(cmd->chanlist[i]); + uint16_t val = le16_to_cpu(devpriv->in_buf[i]); + + /* bipolar data is two's-complement */ + if (comedi_range_is_bipolar(s, range)) + val ^= ((s->maxdata + 1) >> 1); + /* transfer data */ - if (CR_RANGE(s->async->cmd.chanlist[i]) <= 1) { - err = comedi_buf_put - (s->async, - le16_to_cpu(this_usbduxsub->inBuffer[i]) ^ 0x800); - } else { - err = comedi_buf_put - (s->async, - le16_to_cpu(this_usbduxsub->inBuffer[i])); - } + err = comedi_buf_put(s, val); if (unlikely(err == 0)) { /* buffer overflow */ - usbdux_ai_stop(this_usbduxsub, 0); + usbdux_ai_stop(dev, 0); return; } } /* tell comedi that data is there */ s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); } -static int usbduxsub_unlink_OutURBs(struct usbduxsub *usbduxsub_tmp) +static void usbdux_ao_stop(struct comedi_device *dev, int do_unlink) { - int i = 0; - int err = 0; + struct usbdux_private *devpriv = dev->private; - if (usbduxsub_tmp && usbduxsub_tmp->urbOut) { - for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) { - if (usbduxsub_tmp->urbOut[i]) - usb_kill_urb(usbduxsub_tmp->urbOut[i]); + if (do_unlink && devpriv->ao_urbs) + usbdux_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs); - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: usbdux: unlinked OutURB %d: res=%d\n", - i, err); - } - } - return err; + devpriv->ao_cmd_running = 0; } -/* This will cancel a running acquisition operation - * in any context. - */ -static int usbdux_ao_stop(struct usbduxsub *this_usbduxsub, int do_unlink) -{ - int ret = 0; - - if (!this_usbduxsub) - return -EFAULT; - dev_dbg(&this_usbduxsub->interface->dev, "comedi: usbdux_ao_cancel\n"); - - if (do_unlink) - ret = usbduxsub_unlink_OutURBs(this_usbduxsub); - - this_usbduxsub->ao_cmd_running = 0; - - return ret; -} - -/* force unlink, is called by comedi */ static int usbdux_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub = dev->private; - int res = 0; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; /* prevent other CPUs from submitting a command just now */ - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + down(&devpriv->sem); /* unlink only if it is really running */ - res = usbdux_ao_stop(this_usbduxsub, this_usbduxsub->ao_cmd_running); - up(&this_usbduxsub->sem); - return res; + usbdux_ao_stop(dev, devpriv->ao_cmd_running); + up(&devpriv->sem); + + return 0; } -static void usbduxsub_ao_IsocIrq(struct urb *urb) +static void usbduxsub_ao_isoc_irq(struct urb *urb) { - int i, ret; - int8_t *datap; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - - s = this_comedidev->subdevices + SUBDEV_DA; + struct comedi_device *dev = urb->context; + struct comedi_subdevice *s = dev->write_subdev; + struct usbdux_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + uint8_t *datap; + int ret; + int i; switch (urb->status) { case 0: @@ -621,311 +427,130 @@ static void usbduxsub_ao_IsocIrq(struct urb *urb) case -ECONNABORTED: /* after an unlink command, unplug, ... etc */ /* no unlink needed here. Already shutting down. */ - if (this_usbduxsub->ao_cmd_running) { + if (devpriv->ao_cmd_running) { s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); - usbdux_ao_stop(this_usbduxsub, 0); + comedi_event(dev, s); + usbdux_ao_stop(dev, 0); } return; default: /* a real error */ - if (this_usbduxsub->ao_cmd_running) { - dev_err(&urb->dev->dev, - "comedi_: Non-zero urb status received in ao " - "intr context: %d\n", urb->status); + if (devpriv->ao_cmd_running) { + dev_err(dev->class_dev, + "Non-zero urb status received in ao intr context: %d\n", + urb->status); s->async->events |= COMEDI_CB_ERROR; s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* we do an unlink if we are in the high speed mode */ - usbdux_ao_stop(this_usbduxsub, 0); + usbdux_ao_stop(dev, 0); } return; } /* are we actually running? */ - if (!(this_usbduxsub->ao_cmd_running)) + if (!devpriv->ao_cmd_running) return; /* normal operation: executing a command in this subdevice */ - this_usbduxsub->ao_counter--; - if ((int)this_usbduxsub->ao_counter <= 0) { + devpriv->ao_counter--; + if ((int)devpriv->ao_counter <= 0) { /* timer zero */ - this_usbduxsub->ao_counter = this_usbduxsub->ao_timer; + devpriv->ao_counter = devpriv->ao_timer; /* handle non continous acquisition */ - if (!(this_usbduxsub->ao_continous)) { + if (cmd->stop_src == TRIG_COUNT) { /* fixed number of samples */ - this_usbduxsub->ao_sample_count--; - if (this_usbduxsub->ao_sample_count < 0) { + devpriv->ao_sample_count--; + if (devpriv->ao_sample_count < 0) { /* all samples transmitted */ - usbdux_ao_stop(this_usbduxsub, 0); + usbdux_ao_stop(dev, 0); s->async->events |= COMEDI_CB_EOA; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* no resubmit of the urb */ return; } } + /* transmit data to the USB bus */ - ((uint8_t *) (urb->transfer_buffer))[0] = - s->async->cmd.chanlist_len; - for (i = 0; i < s->async->cmd.chanlist_len; i++) { - short temp; - if (i >= NUMOUTCHANNELS) - break; + datap = urb->transfer_buffer; + *datap++ = cmd->chanlist_len; + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned short val; - /* pointer to the DA */ - datap = - (&(((int8_t *) urb->transfer_buffer)[i * 3 + 1])); - /* get the data from comedi */ - ret = comedi_buf_get(s->async, &temp); - datap[0] = temp; - datap[1] = temp >> 8; - datap[2] = this_usbduxsub->dac_commands[i]; - /* printk("data[0]=%x, data[1]=%x, data[2]=%x\n", */ - /* datap[0],datap[1],datap[2]); */ + ret = comedi_buf_get(s, &val); if (ret < 0) { - dev_err(&urb->dev->dev, - "comedi: buffer underflow\n"); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_OVERFLOW; + dev_err(dev->class_dev, "buffer underflow\n"); + s->async->events |= (COMEDI_CB_EOA | + COMEDI_CB_OVERFLOW); } - /* transmit data to comedi */ + /* pointer to the DA */ + *datap++ = val & 0xff; + *datap++ = (val >> 8) & 0xff; + *datap++ = chan << 6; + devpriv->ao_readback[chan] = val; + s->async->events |= COMEDI_CB_BLOCK; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); } } urb->transfer_buffer_length = SIZEOUTBUF; - urb->dev = this_usbduxsub->usbdev; + urb->dev = comedi_to_usb_dev(dev); urb->status = 0; - if (this_usbduxsub->ao_cmd_running) { - if (this_usbduxsub->high_speed) { - /* uframes */ - urb->interval = 8; - } else { - /* frames */ - urb->interval = 1; - } + if (devpriv->ao_cmd_running) { + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ urb->number_of_packets = 1; urb->iso_frame_desc[0].offset = 0; urb->iso_frame_desc[0].length = SIZEOUTBUF; urb->iso_frame_desc[0].status = 0; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { - dev_err(&urb->dev->dev, - "comedi_: ao urb resubm failed in int-cont. " - "ret=%d", ret); + dev_err(dev->class_dev, + "ao urb resubm failed in int-cont. ret=%d", + ret); if (ret == EL2NSYNC) - dev_err(&urb->dev->dev, - "buggy USB host controller or bug in " - "IRQ handling!\n"); + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handling!\n"); s->async->events |= COMEDI_CB_EOA; s->async->events |= COMEDI_CB_ERROR; - comedi_event(this_usbduxsub->comedidev, s); + comedi_event(dev, s); /* don't do an unlink here */ - usbdux_ao_stop(this_usbduxsub, 0); + usbdux_ao_stop(dev, 0); } } } -static int usbduxsub_start(struct usbduxsub *usbduxsub) -{ - int errcode = 0; - uint8_t local_transfer_buffer[16]; - - /* 7f92 to zero */ - local_transfer_buffer[0] = 0; - errcode = usb_control_msg(usbduxsub->usbdev, - /* create a pipe for a control transfer */ - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* bRequest, "Firmware" */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* Value */ - USBDUXSUB_CPUCS, - /* Index */ - 0x0000, - /* address of the transfer buffer */ - local_transfer_buffer, - /* Length */ - 1, - /* Timeout */ - BULK_TIMEOUT); - if (errcode < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: control msg failed (start)\n"); - return errcode; - } - return 0; -} - -static int usbduxsub_stop(struct usbduxsub *usbduxsub) -{ - int errcode = 0; - - uint8_t local_transfer_buffer[16]; - - /* 7f92 to one */ - local_transfer_buffer[0] = 1; - errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* bRequest, "Firmware" */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* Value */ - USBDUXSUB_CPUCS, - /* Index */ - 0x0000, local_transfer_buffer, - /* Length */ - 1, - /* Timeout */ - BULK_TIMEOUT); - if (errcode < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: control msg failed (stop)\n"); - return errcode; - } - return 0; -} - -static int usbduxsub_upload(struct usbduxsub *usbduxsub, - uint8_t *local_transfer_buffer, - unsigned int startAddr, unsigned int len) -{ - int errcode; - - errcode = usb_control_msg(usbduxsub->usbdev, - usb_sndctrlpipe(usbduxsub->usbdev, 0), - /* brequest, firmware */ - USBDUXSUB_FIRMWARE, - /* bmRequestType */ - VENDOR_DIR_OUT, - /* value */ - startAddr, - /* index */ - 0x0000, - /* our local safe buffer */ - local_transfer_buffer, - /* length */ - len, - /* timeout */ - BULK_TIMEOUT); - dev_dbg(&usbduxsub->interface->dev, "comedi_: result=%d\n", errcode); - if (errcode < 0) { - dev_err(&usbduxsub->interface->dev, "comedi_: upload failed\n"); - return errcode; - } - return 0; -} - -#define FIRMWARE_MAX_LEN 0x2000 - -static int firmwareUpload(struct usbduxsub *usbduxsub, - const u8 *firmwareBinary, int sizeFirmware) +static int usbdux_submit_urbs(struct comedi_device *dev, + struct urb **urbs, int num_urbs, + int input_urb) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + struct urb *urb; int ret; - uint8_t *fwBuf; - - if (!firmwareBinary) - return 0; - - if (sizeFirmware > FIRMWARE_MAX_LEN) { - dev_err(&usbduxsub->interface->dev, - "usbdux firmware binary it too large for FX2.\n"); - return -ENOMEM; - } - - /* we generate a local buffer for the firmware */ - fwBuf = kmemdup(firmwareBinary, sizeFirmware, GFP_KERNEL); - if (!fwBuf) { - dev_err(&usbduxsub->interface->dev, - "comedi_: mem alloc for firmware failed\n"); - return -ENOMEM; - } - - ret = usbduxsub_stop(usbduxsub); - if (ret < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: can not stop firmware\n"); - kfree(fwBuf); - return ret; - } - - ret = usbduxsub_upload(usbduxsub, fwBuf, 0, sizeFirmware); - if (ret < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: firmware upload failed\n"); - kfree(fwBuf); - return ret; - } - ret = usbduxsub_start(usbduxsub); - if (ret < 0) { - dev_err(&usbduxsub->interface->dev, - "comedi_: can not start firmware\n"); - kfree(fwBuf); - return ret; - } - kfree(fwBuf); - return 0; -} - -static int usbduxsub_submit_InURBs(struct usbduxsub *usbduxsub) -{ - int i, errFlag; - - if (!usbduxsub) - return -EFAULT; + int i; /* Submit all URBs and start the transfer on the bus */ - for (i = 0; i < usbduxsub->numOfInBuffers; i++) { - /* in case of a resubmission after an unlink... */ - usbduxsub->urbIn[i]->interval = usbduxsub->ai_interval; - usbduxsub->urbIn[i]->context = usbduxsub->comedidev; - usbduxsub->urbIn[i]->dev = usbduxsub->usbdev; - usbduxsub->urbIn[i]->status = 0; - usbduxsub->urbIn[i]->transfer_flags = URB_ISO_ASAP; - dev_dbg(&usbduxsub->interface->dev, - "comedi%d: submitting in-urb[%d]: %p,%p intv=%d\n", - usbduxsub->comedidev->minor, i, - (usbduxsub->urbIn[i]->context), - (usbduxsub->urbIn[i]->dev), - (usbduxsub->urbIn[i]->interval)); - errFlag = usb_submit_urb(usbduxsub->urbIn[i], GFP_ATOMIC); - if (errFlag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: ai: usb_submit_urb(%d) error %d\n", - i, errFlag); - return errFlag; - } - } - return 0; -} - -static int usbduxsub_submit_OutURBs(struct usbduxsub *usbduxsub) -{ - int i, errFlag; - - if (!usbduxsub) - return -EFAULT; + for (i = 0; i < num_urbs; i++) { + urb = urbs[i]; - for (i = 0; i < usbduxsub->numOfOutBuffers; i++) { - dev_dbg(&usbduxsub->interface->dev, - "comedi_: submitting out-urb[%d]\n", i); /* in case of a resubmission after an unlink... */ - usbduxsub->urbOut[i]->context = usbduxsub->comedidev; - usbduxsub->urbOut[i]->dev = usbduxsub->usbdev; - usbduxsub->urbOut[i]->status = 0; - usbduxsub->urbOut[i]->transfer_flags = URB_ISO_ASAP; - errFlag = usb_submit_urb(usbduxsub->urbOut[i], GFP_ATOMIC); - if (errFlag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: ao: usb_submit_urb(%d) error %d\n", - i, errFlag); - return errFlag; - } + if (input_urb) + urb->interval = devpriv->ai_interval; + urb->context = dev; + urb->dev = usb; + urb->status = 0; + urb->transfer_flags = URB_ISO_ASAP; + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + return ret; } return 0; } @@ -933,78 +558,37 @@ static int usbduxsub_submit_OutURBs(struct usbduxsub *usbduxsub) static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp, i; - unsigned int tmpTimer; - struct usbduxsub *this_usbduxsub = dev->private; - - if (!(this_usbduxsub->probed)) - return -ENODEV; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_cmdtest\n", dev->minor); - - /* make sure triggers are valid */ - /* Only immediate triggers are allowed */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - /* trigger should happen timed */ - tmp = cmd->scan_begin_src; - /* start a new _scan_ with a timer */ - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - /* scanning is continuous */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - /* issue a trigger when scan is finished and start a new scan */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - /* trigger at the end of count events or not, stop condition or not */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + struct usbdux_private *this_usbduxsub = dev->private; + int err = 0, i; + unsigned int tmp_timer; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, 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_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually compatible - * note that mutual compatibility is not an issue here - */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + /* Step 3: check if arguments are trivially valid */ - if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* internal trigger */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + + if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */ + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); if (cmd->scan_begin_src == TRIG_TIMER) { if (this_usbduxsub->high_speed) { @@ -1019,51 +603,35 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, while (i < (cmd->chanlist_len)) i = i * 2; - if (cmd->scan_begin_arg < (1000000 / 8 * i)) { - cmd->scan_begin_arg = 1000000 / 8 * i; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + 1000000 / 8 * i); /* now calc the real sampling rate with all the * rounding errors */ - tmpTimer = + tmp_timer = ((unsigned int)(cmd->scan_begin_arg / 125000)) * 125000; - if (cmd->scan_begin_arg != tmpTimer) { - cmd->scan_begin_arg = tmpTimer; - err++; - } } else { /* full speed */ /* 1kHz scans every USB frame */ - if (cmd->scan_begin_arg < 1000000) { - cmd->scan_begin_arg = 1000000; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + 1000000); /* * calc the real sampling rate with the rounding errors */ - tmpTimer = ((unsigned int)(cmd->scan_begin_arg / + tmp_timer = ((unsigned int)(cmd->scan_begin_arg / 1000000)) * 1000000; - if (cmd->scan_begin_arg != tmpTimer) { - cmd->scan_begin_arg = tmpTimer; - err++; - } } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, + tmp_timer); } - /* the same argument */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + + 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_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } if (err) @@ -1076,228 +644,150 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, * creates the ADC command for the MAX1271 * range is the range value from comedi */ -static int8_t create_adc_command(unsigned int chan, int range) +static uint8_t create_adc_command(unsigned int chan, unsigned int range) { - int8_t p = (range <= 1); - int8_t r = ((range % 2) == 0); + uint8_t p = (range <= 1); + uint8_t r = ((range % 2) == 0); + return (chan << 4) | ((p == 1) << 2) | ((r == 1) << 3); } -/* bulk transfers to usbdux */ +static int send_dux_commands(struct comedi_device *dev, unsigned int cmd_type) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + int nsent; -#define SENDADCOMMANDS 0 -#define SENDDACOMMANDS 1 -#define SENDDIOCONFIGCOMMAND 2 -#define SENDDIOBITSCOMMAND 3 -#define SENDSINGLEAD 4 -#define READCOUNTERCOMMAND 5 -#define WRITECOUNTERCOMMAND 6 -#define SENDPWMON 7 -#define SENDPWMOFF 8 + devpriv->dux_commands[0] = cmd_type; -static int send_dux_commands(struct usbduxsub *this_usbduxsub, int cmd_type) -{ - int result, nsent; - - this_usbduxsub->dux_commands[0] = cmd_type; -#ifdef NOISY_DUX_DEBUGBUG - printk(KERN_DEBUG "comedi%d: usbdux: dux_commands: ", - this_usbduxsub->comedidev->minor); - for (result = 0; result < SIZEOFDUXBUFFER; result++) - printk(" %02x", this_usbduxsub->dux_commands[result]); - printk("\n"); -#endif - result = usb_bulk_msg(this_usbduxsub->usbdev, - usb_sndbulkpipe(this_usbduxsub->usbdev, - COMMAND_OUT_EP), - this_usbduxsub->dux_commands, SIZEOFDUXBUFFER, - &nsent, BULK_TIMEOUT); - if (result < 0) - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "could not transmit dux_command to the usb-device, " - "err=%d\n", this_usbduxsub->comedidev->minor, result); - - return result; + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1), + devpriv->dux_commands, SIZEOFDUXBUFFER, + &nsent, BULK_TIMEOUT); } -static int receive_dux_commands(struct usbduxsub *this_usbduxsub, int command) +static int receive_dux_commands(struct comedi_device *dev, unsigned int command) { - int result = (-EFAULT); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + int ret; int nrec; int i; for (i = 0; i < RETRIES; i++) { - result = usb_bulk_msg(this_usbduxsub->usbdev, - usb_rcvbulkpipe(this_usbduxsub->usbdev, - COMMAND_IN_EP), - this_usbduxsub->insnBuffer, SIZEINSNBUF, + ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8), + devpriv->insn_buf, SIZEINSNBUF, &nrec, BULK_TIMEOUT); - if (result < 0) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "insn: USB error %d while receiving DUX command" - "\n", this_usbduxsub->comedidev->minor, result); - return result; - } - if (le16_to_cpu(this_usbduxsub->insnBuffer[0]) == command) - return result; + if (ret < 0) + return ret; + if (le16_to_cpu(devpriv->insn_buf[0]) == command) + return ret; } - /* this is only reached if the data has been requested a couple of - * times */ - dev_err(&this_usbduxsub->interface->dev, "comedi%d: insn: " - "wrong data returned from firmware: want cmd %d, got cmd %d.\n", - this_usbduxsub->comedidev->minor, command, - le16_to_cpu(this_usbduxsub->insnBuffer[0])); + /* command not received */ return -EFAULT; } static int usbdux_ai_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { + struct usbdux_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - struct usbduxsub *this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig\n", dev->minor); - - if (trignum != 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig: invalid trignum\n", - dev->minor); - up(&this_usbduxsub->sem); + if (trig_num != cmd->start_arg) return -EINVAL; - } - if (!(this_usbduxsub->ai_cmd_running)) { - this_usbduxsub->ai_cmd_running = 1; - ret = usbduxsub_submit_InURBs(this_usbduxsub); + + down(&devpriv->sem); + + if (!devpriv->ai_cmd_running) { + devpriv->ai_cmd_running = 1; + ret = usbdux_submit_urbs(dev, devpriv->ai_urbs, + devpriv->n_ai_urbs, 1); if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_inttrig: " - "urbSubmit: err=%d\n", dev->minor, ret); - this_usbduxsub->ai_cmd_running = 0; - up(&this_usbduxsub->sem); - return ret; + devpriv->ai_cmd_running = 0; + goto ai_trig_exit; } s->async->inttrig = NULL; } else { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ai_inttrig but acqu is already running\n", - dev->minor); + ret = -EBUSY; } - up(&this_usbduxsub->sem); - return 1; + +ai_trig_exit: + up(&devpriv->sem); + return ret; } static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct usbdux_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - unsigned int chan, range; - int i, ret; - struct usbduxsub *this_usbduxsub = dev->private; - int result; - - if (!this_usbduxsub) - return -EFAULT; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ai_cmd\n", dev->minor); + int len = cmd->chanlist_len; + int ret = -EBUSY; + int i; /* block other CPUs from starting an ai_cmd */ - down(&this_usbduxsub->sem); + down(&devpriv->sem); + + if (devpriv->ai_cmd_running) + goto ai_cmd_exit; - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ai_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: " - "ai_cmd not possible. Another ai_cmd is running.\n", - dev->minor); - up(&this_usbduxsub->sem); - return -EBUSY; - } /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; - this_usbduxsub->dux_commands[1] = cmd->chanlist_len; - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - range = CR_RANGE(cmd->chanlist[i]); - if (i >= NUMCHANNELS) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: channel list too long\n", - dev->minor); - break; - } - this_usbduxsub->dux_commands[i + 2] = - create_adc_command(chan, range); - } - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi %d: sending commands to the usb device: size=%u\n", - dev->minor, NUMCHANNELS); + devpriv->dux_commands[1] = len; + for (i = 0; i < len; ++i) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned int range = CR_RANGE(cmd->chanlist[i]); - result = send_dux_commands(this_usbduxsub, SENDADCOMMANDS); - if (result < 0) { - up(&this_usbduxsub->sem); - return result; + devpriv->dux_commands[i + 2] = create_adc_command(chan, range); } - if (this_usbduxsub->high_speed) { + ret = send_dux_commands(dev, USBDUX_CMD_MULT_AI); + if (ret < 0) + goto ai_cmd_exit; + + if (devpriv->high_speed) { /* * every channel gets a time window of 125us. Thus, if we * sample all 8 channels we need 1ms. If we sample only one * channel we need only 125us */ - this_usbduxsub->ai_interval = 1; + devpriv->ai_interval = 1; /* find a power of 2 for the interval */ - while ((this_usbduxsub->ai_interval) < (cmd->chanlist_len)) { - this_usbduxsub->ai_interval = - (this_usbduxsub->ai_interval) * 2; - } - this_usbduxsub->ai_timer = cmd->scan_begin_arg / (125000 * - (this_usbduxsub-> - ai_interval)); + while (devpriv->ai_interval < len) + devpriv->ai_interval *= 2; + + devpriv->ai_timer = cmd->scan_begin_arg / + (125000 * devpriv->ai_interval); } else { /* interval always 1ms */ - this_usbduxsub->ai_interval = 1; - this_usbduxsub->ai_timer = cmd->scan_begin_arg / 1000000; + devpriv->ai_interval = 1; + devpriv->ai_timer = cmd->scan_begin_arg / 1000000; } - if (this_usbduxsub->ai_timer < 1) { - dev_err(&this_usbduxsub->interface->dev, "comedi%d: ai_cmd: " - "timer=%d, scan_begin_arg=%d. " - "Not properly tested by cmdtest?\n", dev->minor, - this_usbduxsub->ai_timer, cmd->scan_begin_arg); - up(&this_usbduxsub->sem); - return -EINVAL; + if (devpriv->ai_timer < 1) { + ret = -EINVAL; + goto ai_cmd_exit; } - this_usbduxsub->ai_counter = this_usbduxsub->ai_timer; + + devpriv->ai_counter = devpriv->ai_timer; if (cmd->stop_src == TRIG_COUNT) { /* data arrives as one packet */ - this_usbduxsub->ai_sample_count = cmd->stop_arg; - this_usbduxsub->ai_continous = 0; + devpriv->ai_sample_count = cmd->stop_arg; } else { /* continous acquisition */ - this_usbduxsub->ai_continous = 1; - this_usbduxsub->ai_sample_count = 0; + devpriv->ai_sample_count = 0; } if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ - this_usbduxsub->ai_cmd_running = 1; - ret = usbduxsub_submit_InURBs(this_usbduxsub); + devpriv->ai_cmd_running = 1; + ret = usbdux_submit_urbs(dev, devpriv->ai_urbs, + devpriv->n_ai_urbs, 1); if (ret < 0) { - this_usbduxsub->ai_cmd_running = 0; + devpriv->ai_cmd_running = 0; /* fixme: unlink here?? */ - up(&this_usbduxsub->sem); - return ret; + goto ai_cmd_exit; } s->async->inttrig = NULL; } else { @@ -1306,321 +796,225 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* wait for an internal signal */ s->async->inttrig = usbdux_ai_inttrig; } - up(&this_usbduxsub->sem); - return 0; + +ai_cmd_exit: + up(&devpriv->sem); + + return ret; } /* Mode 0 is used to get a single conversion on demand */ static int usbdux_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + int ret = -EBUSY; int i; - unsigned int one = 0; - int chan, range; - int err; - struct usbduxsub *this_usbduxsub = dev->private; - - if (!this_usbduxsub) - return 0; - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ai_insn_read, insn->n=%d, insn->subdev=%d\n", - dev->minor, insn->n, insn->subdev); + down(&devpriv->sem); - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ai_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ai_insn_read not possible. " - "Async Command is running.\n", dev->minor); - up(&this_usbduxsub->sem); - return 0; - } + if (devpriv->ai_cmd_running) + goto ai_read_exit; - /* sample one channel */ - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); /* set command for the first channel */ - this_usbduxsub->dux_commands[1] = create_adc_command(chan, range); + devpriv->dux_commands[1] = create_adc_command(chan, range); /* adc commands */ - err = send_dux_commands(this_usbduxsub, SENDSINGLEAD); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } + ret = send_dux_commands(dev, USBDUX_CMD_SINGLE_AI); + if (ret < 0) + goto ai_read_exit; for (i = 0; i < insn->n; i++) { - err = receive_dux_commands(this_usbduxsub, SENDSINGLEAD); - if (err < 0) { - up(&this_usbduxsub->sem); - return 0; - } - one = le16_to_cpu(this_usbduxsub->insnBuffer[1]); - if (CR_RANGE(insn->chanspec) <= 1) - one = one ^ 0x800; + ret = receive_dux_commands(dev, USBDUX_CMD_SINGLE_AI); + if (ret < 0) + goto ai_read_exit; + + val = le16_to_cpu(devpriv->insn_buf[1]); + + /* bipolar data is two's-complement */ + if (comedi_range_is_bipolar(s, range)) + val ^= ((s->maxdata + 1) >> 1); - data[i] = one; + data[i] = val; } - up(&this_usbduxsub->sem); - return i; -} -/************************************/ -/* analog out */ +ai_read_exit: + up(&devpriv->sem); + + return ret ? ret : insn->n; +} static int usbdux_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); - struct usbduxsub *this_usbduxsub = dev->private; - - if (!this_usbduxsub) - return -EFAULT; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + down(&devpriv->sem); for (i = 0; i < insn->n; i++) - data[i] = this_usbduxsub->outBuffer[chan]; + data[i] = devpriv->ao_readback[chan]; + up(&devpriv->sem); - up(&this_usbduxsub->sem); - return i; + return insn->n; } static int usbdux_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) { - int i, err; - int chan = CR_CHAN(insn->chanspec); - struct usbduxsub *this_usbduxsub = dev->private; + 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]; + int ret = -EBUSY; + int i; - if (!this_usbduxsub) - return -EFAULT; + down(&devpriv->sem); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write\n", dev->minor); + if (devpriv->ao_cmd_running) + goto ao_write_exit; - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (this_usbduxsub->ao_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write: " - "ERROR: asynchronous ao_cmd is running\n", dev->minor); - up(&this_usbduxsub->sem); - return 0; - } + /* number of channels: 1 */ + devpriv->dux_commands[1] = 1; + /* channel number */ + devpriv->dux_commands[4] = chan << 6; for (i = 0; i < insn->n; i++) { - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_insn_write: data[chan=%d,i=%d]=%d\n", - dev->minor, chan, i, data[i]); + val = data[i]; - /* number of channels: 1 */ - this_usbduxsub->dux_commands[1] = 1; /* one 16 bit value */ - *((int16_t *) (this_usbduxsub->dux_commands + 2)) = - cpu_to_le16(data[i]); - this_usbduxsub->outBuffer[chan] = data[i]; - /* channel number */ - this_usbduxsub->dux_commands[4] = (chan << 6); - err = send_dux_commands(this_usbduxsub, SENDDACOMMANDS); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } + *p = cpu_to_le16(val); + + ret = send_dux_commands(dev, USBDUX_CMD_AO); + if (ret < 0) + goto ao_write_exit; } - up(&this_usbduxsub->sem); + devpriv->ao_readback[chan] = val; + +ao_write_exit: + up(&devpriv->sem); - return i; + return ret ? ret : insn->n; } static int usbdux_ao_inttrig(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int trignum) + struct comedi_subdevice *s, + unsigned int trig_num) { + struct usbdux_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - struct usbduxsub *this_usbduxsub = dev->private; - if (!this_usbduxsub) - return -EFAULT; - - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - if (trignum != 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ao_inttrig: invalid trignum\n", - dev->minor); + if (trig_num != cmd->start_arg) return -EINVAL; - } - if (!(this_usbduxsub->ao_cmd_running)) { - this_usbduxsub->ao_cmd_running = 1; - ret = usbduxsub_submit_OutURBs(this_usbduxsub); + + down(&devpriv->sem); + + if (!devpriv->ao_cmd_running) { + devpriv->ao_cmd_running = 1; + ret = usbdux_submit_urbs(dev, devpriv->ao_urbs, + devpriv->n_ao_urbs, 0); if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ao_inttrig: submitURB: " - "err=%d\n", dev->minor, ret); - this_usbduxsub->ao_cmd_running = 0; - up(&this_usbduxsub->sem); - return ret; + devpriv->ao_cmd_running = 0; + goto ao_trig_exit; } s->async->inttrig = NULL; } else { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: ao_inttrig but acqu is already running.\n", - dev->minor); + ret = -EBUSY; } - up(&this_usbduxsub->sem); - return 1; + +ao_trig_exit: + up(&devpriv->sem); + return ret; } static int usbdux_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp; - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *this_usbduxsub = dev->private; + int err = 0; + unsigned int flags; if (!this_usbduxsub) return -EFAULT; - if (!(this_usbduxsub->probed)) - return -ENODEV; - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: usbdux_ao_cmdtest\n", dev->minor); + /* Step 1 : check if triggers are trivially valid */ - /* make sure triggers are valid */ - /* Only immediate triggers are allowed */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - /* trigger should happen timed */ - tmp = cmd->scan_begin_src; - /* just now we scan also in the high speed mode every frame */ - /* this is due to ehci driver limitations */ if (0) { /* (this_usbduxsub->high_speed) */ - /* start immediately a new scan */ /* the sampling rate is set by the coversion rate */ - cmd->scan_begin_src &= TRIG_FOLLOW; + flags = TRIG_FOLLOW; } else { /* start a new scan (output at once) with a timer */ - cmd->scan_begin_src &= TRIG_TIMER; + flags = TRIG_TIMER; } - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags); - /* scanning is continuous */ - tmp = cmd->convert_src; - /* we always output at 1kHz just now all channels at once */ if (0) { /* (this_usbduxsub->high_speed) */ /* - * in usb-2.0 only one conversion it transmitted but with 8kHz/n + * in usb-2.0 only one conversion it transmitted + * but with 8kHz/n */ - cmd->convert_src &= TRIG_TIMER; + flags = TRIG_TIMER; } else { - /* all conversion events happen simultaneously with a rate of - * 1kHz/n */ - cmd->convert_src &= TRIG_NOW; + /* + * all conversion events happen simultaneously with + * a rate of 1kHz/n + */ + flags = TRIG_NOW; } - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - /* issue a trigger when scan is finished and start a new scan */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, flags); - /* trigger at the end of count events or not, stop condition or not */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + 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 2: make sure trigger sources are unique and mutually compatible - * note that mutual compatibility is not an issue here - */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); - if (cmd->scan_begin_src == TRIG_FOLLOW) { - /* internal trigger */ - if (cmd->scan_begin_arg != 0) { - cmd->scan_begin_arg = 0; - err++; - } - } + if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */ + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + 1000000); - if (cmd->scan_begin_src == TRIG_TIMER) { - /* timer */ - if (cmd->scan_begin_arg < 1000000) { - cmd->scan_begin_arg = 1000000; - err++; - } - } /* not used now, is for later use */ - if (cmd->convert_src == TRIG_TIMER) { - if (cmd->convert_arg < 125000) { - cmd->convert_arg = 125000; - err++; - } - } + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 125000); - /* the same argument */ - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + 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_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); } - dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: err=%d, " - "scan_begin_src=%d, scan_begin_arg=%d, convert_src=%d, " - "convert_arg=%d\n", dev->minor, err, cmd->scan_begin_src, - cmd->scan_begin_arg, cmd->convert_src, cmd->convert_arg); - if (err) return 3; @@ -1629,99 +1023,63 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct usbdux_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - unsigned int chan, gain; - int i, ret; - struct usbduxsub *this_usbduxsub = dev->private; + int ret = -EBUSY; - if (!this_usbduxsub) - return -EFAULT; + down(&devpriv->sem); - down(&this_usbduxsub->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s\n", dev->minor, __func__); + if (devpriv->ao_cmd_running) + goto ao_cmd_exit; /* set current channel of the running acquisition to zero */ s->async->cur_chan = 0; - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - gain = CR_RANGE(cmd->chanlist[i]); - if (i >= NUMOUTCHANNELS) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: %s: channel list too long\n", - dev->minor, __func__); - break; - } - this_usbduxsub->dac_commands[i] = (chan << 6); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: dac command for ch %d is %x\n", - dev->minor, i, this_usbduxsub->dac_commands[i]); - } /* we count in steps of 1ms (125us) */ /* 125us mode not used yet */ - if (0) { /* (this_usbduxsub->high_speed) */ + if (0) { /* (devpriv->high_speed) */ /* 125us */ /* timing of the conversion itself: every 125 us */ - this_usbduxsub->ao_timer = cmd->convert_arg / 125000; + devpriv->ao_timer = cmd->convert_arg / 125000; } else { /* 1ms */ /* timing of the scan: we get all channels at once */ - this_usbduxsub->ao_timer = cmd->scan_begin_arg / 1000000; - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: scan_begin_src=%d, scan_begin_arg=%d, " - "convert_src=%d, convert_arg=%d\n", dev->minor, - cmd->scan_begin_src, cmd->scan_begin_arg, - cmd->convert_src, cmd->convert_arg); - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: ao_timer=%d (ms)\n", - dev->minor, this_usbduxsub->ao_timer); - if (this_usbduxsub->ao_timer < 1) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: usbdux: ao_timer=%d, " - "scan_begin_arg=%d. " - "Not properly tested by cmdtest?\n", - dev->minor, this_usbduxsub->ao_timer, - cmd->scan_begin_arg); - up(&this_usbduxsub->sem); - return -EINVAL; + devpriv->ao_timer = cmd->scan_begin_arg / 1000000; + if (devpriv->ao_timer < 1) { + ret = -EINVAL; + goto ao_cmd_exit; } } - this_usbduxsub->ao_counter = this_usbduxsub->ao_timer; + + devpriv->ao_counter = devpriv->ao_timer; if (cmd->stop_src == TRIG_COUNT) { /* not continuous */ /* counter */ /* high speed also scans everything at once */ - if (0) { /* (this_usbduxsub->high_speed) */ - this_usbduxsub->ao_sample_count = - (cmd->stop_arg) * (cmd->scan_end_arg); + if (0) { /* (devpriv->high_speed) */ + devpriv->ao_sample_count = cmd->stop_arg * + cmd->scan_end_arg; } else { /* there's no scan as the scan has been */ /* perf inside the FX2 */ /* data arrives as one packet */ - this_usbduxsub->ao_sample_count = cmd->stop_arg; + devpriv->ao_sample_count = cmd->stop_arg; } - this_usbduxsub->ao_continous = 0; } else { /* continous acquisition */ - this_usbduxsub->ao_continous = 1; - this_usbduxsub->ao_sample_count = 0; + devpriv->ao_sample_count = 0; } if (cmd->start_src == TRIG_NOW) { /* enable this acquisition operation */ - this_usbduxsub->ao_cmd_running = 1; - ret = usbduxsub_submit_OutURBs(this_usbduxsub); + devpriv->ao_cmd_running = 1; + ret = usbdux_submit_urbs(dev, devpriv->ao_urbs, + devpriv->n_ao_urbs, 0); if (ret < 0) { - this_usbduxsub->ao_cmd_running = 0; + devpriv->ao_cmd_running = 0; /* fixme: unlink here?? */ - up(&this_usbduxsub->sem); - return ret; + goto ao_cmd_exit; } s->async->inttrig = NULL; } else { @@ -1731,152 +1089,121 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) s->async->inttrig = usbdux_ao_inttrig; } - up(&this_usbduxsub->sem); - return 0; +ao_cmd_exit: + up(&devpriv->sem); + + return ret; } static int usbdux_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + int ret; - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; - switch (data[0]) { - case INSN_CONFIG_DIO_OUTPUT: - s->io_bits |= 1 << chan; /* 1 means Out */ - break; - case INSN_CONFIG_DIO_INPUT: - s->io_bits &= ~(1 << chan); - break; - case INSN_CONFIG_DIO_QUERY: - data[1] = - (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; - break; - default: - return -EINVAL; - break; - } - /* we don't tell the firmware here as it would take 8 frames */ - /* to submit the information. We do it in the insn_bits. */ + /* + * We don't tell the firmware here as it would take 8 frames + * to submit the information. We do it in the insn_bits. + */ return insn->n; } static int usbdux_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; - int err; + struct usbdux_private *devpriv = dev->private; + int ret; - if (!this_usbduxsub) - return -EFAULT; + down(&devpriv->sem); - if (insn->n != 2) - return -EINVAL; + comedi_dio_update_state(s, data); - down(&this_usbduxsub->sem); + /* Always update the hardware. See the (*insn_config). */ + devpriv->dux_commands[1] = s->io_bits; + devpriv->dux_commands[2] = s->state; - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + /* + * This command also tells the firmware to return + * the digital input lines. + */ + ret = send_dux_commands(dev, USBDUX_CMD_DIO_BITS); + if (ret < 0) + goto dio_exit; + ret = receive_dux_commands(dev, USBDUX_CMD_DIO_BITS); + if (ret < 0) + goto dio_exit; - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - this_usbduxsub->dux_commands[1] = s->io_bits; - this_usbduxsub->dux_commands[2] = s->state; - - /* This command also tells the firmware to return */ - /* the digital input lines */ - err = send_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } - err = receive_dux_commands(this_usbduxsub, SENDDIOBITSCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } + data[1] = le16_to_cpu(devpriv->insn_buf[1]); - data[1] = le16_to_cpu(this_usbduxsub->insnBuffer[1]); - up(&this_usbduxsub->sem); - return 2; +dio_exit: + up(&devpriv->sem); + + return ret ? ret : insn->n; } -/* reads the 4 counters, only two are used just now */ static int usbdux_counter_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; - int chan = insn->chanspec; - int err; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int ret = 0; + int i; - down(&this_usbduxsub->sem); + down(&devpriv->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + for (i = 0; i < insn->n; i++) { + ret = send_dux_commands(dev, USBDUX_CMD_TIMER_RD); + if (ret < 0) + goto counter_read_exit; + ret = receive_dux_commands(dev, USBDUX_CMD_TIMER_RD); + if (ret < 0) + goto counter_read_exit; - err = send_dux_commands(this_usbduxsub, READCOUNTERCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; + data[i] = le16_to_cpu(devpriv->insn_buf[chan + 1]); } - err = receive_dux_commands(this_usbduxsub, READCOUNTERCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; - } +counter_read_exit: + up(&devpriv->sem); - data[0] = le16_to_cpu(this_usbduxsub->insnBuffer[chan + 1]); - up(&this_usbduxsub->sem); - return 1; + return ret ? ret : insn->n; } static int usbdux_counter_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; - int err; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + uint16_t *p = (uint16_t *)&devpriv->dux_commands[2]; + int ret = 0; + int i; - down(&this_usbduxsub->sem); + down(&devpriv->sem); - if (!(this_usbduxsub->probed)) { - up(&this_usbduxsub->sem); - return -ENODEV; - } + devpriv->dux_commands[1] = chan; - this_usbduxsub->dux_commands[1] = insn->chanspec; - *((int16_t *) (this_usbduxsub->dux_commands + 2)) = cpu_to_le16(*data); + for (i = 0; i < insn->n; i++) { + *p = cpu_to_le16(data[i]); - err = send_dux_commands(this_usbduxsub, WRITECOUNTERCOMMAND); - if (err < 0) { - up(&this_usbduxsub->sem); - return err; + ret = send_dux_commands(dev, USBDUX_CMD_TIMER_WR); + if (ret < 0) + break; } - up(&this_usbduxsub->sem); + up(&devpriv->sem); - return 1; + return ret ? ret : insn->n; } static int usbdux_counter_config(struct comedi_device *dev, @@ -1887,76 +1214,43 @@ static int usbdux_counter_config(struct comedi_device *dev, return 2; } -/***********************************/ -/* PWM */ - -static int usbduxsub_unlink_PwmURBs(struct usbduxsub *usbduxsub_tmp) +static void usbduxsub_unlink_pwm_urbs(struct comedi_device *dev) { - int err = 0; + struct usbdux_private *devpriv = dev->private; - if (usbduxsub_tmp && usbduxsub_tmp->urbPwm) { - if (usbduxsub_tmp->urbPwm) - usb_kill_urb(usbduxsub_tmp->urbPwm); - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi: unlinked PwmURB: res=%d\n", err); - } - return err; + usb_kill_urb(devpriv->pwm_urb); } -/* This cancels a running acquisition operation - * in any context. - */ -static int usbdux_pwm_stop(struct usbduxsub *this_usbduxsub, int do_unlink) +static void usbdux_pwm_stop(struct comedi_device *dev, int do_unlink) { - int ret = 0; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; - dev_dbg(&this_usbduxsub->interface->dev, "comedi: %s\n", __func__); if (do_unlink) - ret = usbduxsub_unlink_PwmURBs(this_usbduxsub); + usbduxsub_unlink_pwm_urbs(dev); - this_usbduxsub->pwm_cmd_running = 0; - - return ret; + devpriv->pwm_cmd_running = 0; } -/* force unlink - is called by comedi */ static int usbdux_pwm_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct usbduxsub *this_usbduxsub = dev->private; - int res = 0; + struct usbdux_private *devpriv = dev->private; + int ret; + down(&devpriv->sem); /* unlink only if it is really running */ - res = usbdux_pwm_stop(this_usbduxsub, this_usbduxsub->pwm_cmd_running); - - dev_dbg(&this_usbduxsub->interface->dev, - "comedi %d: sending pwm off command to the usb device.\n", - dev->minor); - res = send_dux_commands(this_usbduxsub, SENDPWMOFF); - if (res < 0) - return res; + usbdux_pwm_stop(dev, devpriv->pwm_cmd_running); + ret = send_dux_commands(dev, USBDUX_CMD_PWM_OFF); + up(&devpriv->sem); - return res; + return ret; } static void usbduxsub_pwm_irq(struct urb *urb) { + struct comedi_device *dev = urb->context; + struct usbdux_private *devpriv = dev->private; int ret; - struct usbduxsub *this_usbduxsub; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - - /* printk(KERN_DEBUG "PWM: IRQ\n"); */ - - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - /* the private structure of the subdevice is struct usbduxsub */ - this_usbduxsub = this_comedidev->private; - - s = this_comedidev->subdevices + SUBDEV_DA; switch (urb->status) { case 0: @@ -1971,220 +1265,171 @@ static void usbduxsub_pwm_irq(struct urb *urb) * after an unlink command, unplug, ... etc * no unlink needed here. Already shutting down. */ - if (this_usbduxsub->pwm_cmd_running) - usbdux_pwm_stop(this_usbduxsub, 0); + if (devpriv->pwm_cmd_running) + usbdux_pwm_stop(dev, 0); return; default: /* a real error */ - if (this_usbduxsub->pwm_cmd_running) { - dev_err(&this_usbduxsub->interface->dev, - "comedi_: Non-zero urb status received in " - "pwm intr context: %d\n", urb->status); - usbdux_pwm_stop(this_usbduxsub, 0); + if (devpriv->pwm_cmd_running) { + dev_err(dev->class_dev, + "Non-zero urb status received in pwm intr context: %d\n", + urb->status); + usbdux_pwm_stop(dev, 0); } return; } /* are we actually running? */ - if (!(this_usbduxsub->pwm_cmd_running)) + if (!devpriv->pwm_cmd_running) return; - urb->transfer_buffer_length = this_usbduxsub->sizePwmBuf; - urb->dev = this_usbduxsub->usbdev; + urb->transfer_buffer_length = devpriv->pwm_buf_sz; + urb->dev = comedi_to_usb_dev(dev); urb->status = 0; - if (this_usbduxsub->pwm_cmd_running) { + if (devpriv->pwm_cmd_running) { ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret < 0) { - dev_err(&this_usbduxsub->interface->dev, - "comedi_: pwm urb resubm failed in int-cont. " - "ret=%d", ret); + dev_err(dev->class_dev, + "pwm urb resubm failed in int-cont. ret=%d", + ret); if (ret == EL2NSYNC) - dev_err(&this_usbduxsub->interface->dev, - "buggy USB host controller or bug in " - "IRQ handling!\n"); + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handling!\n"); /* don't do an unlink here */ - usbdux_pwm_stop(this_usbduxsub, 0); + usbdux_pwm_stop(dev, 0); } } } -static int usbduxsub_submit_PwmURBs(struct usbduxsub *usbduxsub) +static int usbduxsub_submit_pwm_urbs(struct comedi_device *dev) { - int errFlag; - - if (!usbduxsub) - return -EFAULT; - - dev_dbg(&usbduxsub->interface->dev, "comedi_: submitting pwm-urb\n"); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + struct urb *urb = devpriv->pwm_urb; /* in case of a resubmission after an unlink... */ - usb_fill_bulk_urb(usbduxsub->urbPwm, - usbduxsub->usbdev, - usb_sndbulkpipe(usbduxsub->usbdev, PWM_EP), - usbduxsub->urbPwm->transfer_buffer, - usbduxsub->sizePwmBuf, usbduxsub_pwm_irq, - usbduxsub->comedidev); - - errFlag = usb_submit_urb(usbduxsub->urbPwm, GFP_ATOMIC); - if (errFlag) { - dev_err(&usbduxsub->interface->dev, - "comedi_: usbdux: pwm: usb_submit_urb error %d\n", - errFlag); - return errFlag; - } - return 0; + usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4), + urb->transfer_buffer, + devpriv->pwm_buf_sz, + usbduxsub_pwm_irq, + dev); + + return usb_submit_urb(urb, GFP_ATOMIC); } static int usbdux_pwm_period(struct comedi_device *dev, - struct comedi_subdevice *s, unsigned int period) + struct comedi_subdevice *s, + unsigned int period) { - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *devpriv = dev->private; int fx2delay = 255; if (period < MIN_PWM_PERIOD) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: illegal period setting for pwm.\n", - dev->minor); return -EAGAIN; } else { - fx2delay = period / ((int)(6 * 512 * (1.0 / 0.033))) - 6; - if (fx2delay > 255) { - dev_err(&this_usbduxsub->interface->dev, - "comedi%d: period %d for pwm is too low.\n", - dev->minor, period); + fx2delay = (period / (6 * 512 * 1000 / 33)) - 6; + if (fx2delay > 255) return -EAGAIN; - } } - this_usbduxsub->pwmDelay = fx2delay; - this_usbduxsub->pwmPeriod = period; - dev_dbg(&this_usbduxsub->interface->dev, "%s: frequ=%d, period=%d\n", - __func__, period, fx2delay); + devpriv->pwm_delay = fx2delay; + devpriv->pwm_period = period; + return 0; } -/* is called from insn so there's no need to do all the sanity checks */ static int usbdux_pwm_start(struct comedi_device *dev, struct comedi_subdevice *s) { - int ret, i; - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *devpriv = dev->private; + int ret = 0; - dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: %s\n", - dev->minor, __func__); + down(&devpriv->sem); - if (this_usbduxsub->pwm_cmd_running) { - /* already running */ - return 0; - } + if (devpriv->pwm_cmd_running) + goto pwm_start_exit; - this_usbduxsub->dux_commands[1] = ((int8_t) this_usbduxsub->pwmDelay); - ret = send_dux_commands(this_usbduxsub, SENDPWMON); + devpriv->dux_commands[1] = devpriv->pwm_delay; + ret = send_dux_commands(dev, USBDUX_CMD_PWM_ON); if (ret < 0) - return ret; + goto pwm_start_exit; /* initialise the buffer */ - for (i = 0; i < this_usbduxsub->sizePwmBuf; i++) - ((char *)(this_usbduxsub->urbPwm->transfer_buffer))[i] = 0; + memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz); - this_usbduxsub->pwm_cmd_running = 1; - ret = usbduxsub_submit_PwmURBs(this_usbduxsub); - if (ret < 0) { - this_usbduxsub->pwm_cmd_running = 0; - return ret; - } - return 0; + devpriv->pwm_cmd_running = 1; + ret = usbduxsub_submit_pwm_urbs(dev); + if (ret < 0) + devpriv->pwm_cmd_running = 0; + +pwm_start_exit: + up(&devpriv->sem); + + return ret; } -/* generates the bit pattern for PWM with the optional sign bit */ -static int usbdux_pwm_pattern(struct comedi_device *dev, - struct comedi_subdevice *s, int channel, - unsigned int value, unsigned int sign) +static void usbdux_pwm_pattern(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, + unsigned int value, + unsigned int sign) { - struct usbduxsub *this_usbduxsub = dev->private; - int i, szbuf; - char *pBuf; - char pwm_mask; - char sgn_mask; - char c; - - if (!this_usbduxsub) - return -EFAULT; + struct usbdux_private *devpriv = dev->private; + char pwm_mask = (1 << chan); /* DIO bit for the PWM data */ + char sgn_mask = (16 << chan); /* DIO bit for the sign */ + char *buf = (char *)(devpriv->pwm_urb->transfer_buffer); + int szbuf = devpriv->pwm_buf_sz; + int i; - /* this is the DIO bit which carries the PWM data */ - pwm_mask = (1 << channel); - /* this is the DIO bit which carries the optional direction bit */ - sgn_mask = (16 << channel); - /* this is the buffer which will be filled with the with bit */ - /* pattern for one period */ - szbuf = this_usbduxsub->sizePwmBuf; - pBuf = (char *)(this_usbduxsub->urbPwm->transfer_buffer); for (i = 0; i < szbuf; i++) { - c = *pBuf; - /* reset bits */ - c = c & (~pwm_mask); - /* set the bit as long as the index is lower than the value */ + char c = *buf; + + c &= ~pwm_mask; if (i < value) - c = c | pwm_mask; - /* set the optional sign bit for a relay */ - if (!sign) { - /* positive value */ - c = c & (~sgn_mask); - } else { - /* negative value */ - c = c | sgn_mask; - } - *(pBuf++) = c; + c |= pwm_mask; + if (!sign) + c &= ~sgn_mask; + else + c |= sgn_mask; + *buf++ = c; } - return 1; } static int usbdux_pwm_write(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); - if (!this_usbduxsub) - return -EFAULT; - - if ((insn->n) != 1) { - /* - * doesn't make sense to have more than one value here because - * it would just overwrite the PWM buffer a couple of times - */ + /* + * It doesn't make sense to support more than one value here + * because it would just overwrite the PWM buffer. + */ + if (insn->n != 1) return -EINVAL; - } /* - * the sign is set via a special INSN only, this gives us 8 bits for - * normal operation - * relay sign 0 by default + * The sign is set via a special INSN only, this gives us 8 bits + * for normal operation, sign is 0 by default. */ - return usbdux_pwm_pattern(dev, s, CR_CHAN(insn->chanspec), data[0], 0); -} + usbdux_pwm_pattern(dev, s, chan, data[0], 0); -static int usbdux_pwm_read(struct comedi_device *x1, - struct comedi_subdevice *x2, struct comedi_insn *x3, - unsigned int *x4) -{ - /* not needed */ - return -EINVAL; -}; + return insn->n; +} -/* switches on/off PWM */ static int usbdux_pwm_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - struct usbduxsub *this_usbduxsub = dev->private; + struct usbdux_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + switch (data[0]) { case INSN_CONFIG_ARM: - /* switch it on */ - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: pwm on\n", dev->minor, __func__); /* * if not zero the PWM is limited to a certain time which is * not supported here @@ -2193,33 +1438,22 @@ static int usbdux_pwm_config(struct comedi_device *dev, return -EINVAL; return usbdux_pwm_start(dev, s); case INSN_CONFIG_DISARM: - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: pwm off\n", dev->minor, __func__); return usbdux_pwm_cancel(dev, s); case INSN_CONFIG_GET_PWM_STATUS: - /* - * to check if the USB transmission has failed or in case PWM - * was limited to n cycles to check if it has terminated - */ - data[1] = this_usbduxsub->pwm_cmd_running; + data[1] = devpriv->pwm_cmd_running; return 0; case INSN_CONFIG_PWM_SET_PERIOD: - dev_dbg(&this_usbduxsub->interface->dev, - "comedi%d: %s: setting period\n", dev->minor, __func__); return usbdux_pwm_period(dev, s, data[1]); case INSN_CONFIG_PWM_GET_PERIOD: - data[1] = this_usbduxsub->pwmPeriod; + data[1] = devpriv->pwm_period; return 0; case INSN_CONFIG_PWM_SET_H_BRIDGE: - /* value in the first byte and the sign in the second for a - relay */ - return usbdux_pwm_pattern(dev, s, - /* the channel number */ - CR_CHAN(insn->chanspec), - /* actual PWM data */ - data[1], - /* just a sign */ - (data[2] != 0)); + /* + * data[1] = value + * data[2] = sign (for a relay) + */ + usbdux_pwm_pattern(dev, s, chan, data[1], (data[2] != 0)); + return 0; case INSN_CONFIG_PWM_GET_H_BRIDGE: /* values are not kept in this driver, nothing to return here */ return -EINVAL; @@ -2227,643 +1461,362 @@ static int usbdux_pwm_config(struct comedi_device *dev, return -EINVAL; } -/* end of PWM */ -/*****************************************************************/ - -static void tidy_up(struct usbduxsub *usbduxsub_tmp) +static int usbdux_firmware_upload(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { - int i; + struct usb_device *usb = comedi_to_usb_dev(dev); + uint8_t *buf; + uint8_t *tmp; + int ret; - if (!usbduxsub_tmp) - return; - dev_dbg(&usbduxsub_tmp->interface->dev, "comedi_: tiding up\n"); + if (!data) + return 0; - /* shows the usb subsystem that the driver is down */ - if (usbduxsub_tmp->interface) - usb_set_intfdata(usbduxsub_tmp->interface, NULL); + if (size > USBDUX_FIRMWARE_MAX_LEN) { + dev_err(dev->class_dev, + "usbdux firmware binary it too large for FX2.\n"); + return -ENOMEM; + } - usbduxsub_tmp->probed = 0; + /* we generate a local buffer for the firmware */ + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; - if (usbduxsub_tmp->urbIn) { - if (usbduxsub_tmp->ai_cmd_running) { - usbduxsub_tmp->ai_cmd_running = 0; - usbduxsub_unlink_InURBs(usbduxsub_tmp); - } - for (i = 0; i < usbduxsub_tmp->numOfInBuffers; i++) { - kfree(usbduxsub_tmp->urbIn[i]->transfer_buffer); - usbduxsub_tmp->urbIn[i]->transfer_buffer = NULL; - usb_kill_urb(usbduxsub_tmp->urbIn[i]); - usb_free_urb(usbduxsub_tmp->urbIn[i]); - usbduxsub_tmp->urbIn[i] = NULL; - } - kfree(usbduxsub_tmp->urbIn); - usbduxsub_tmp->urbIn = NULL; - } - if (usbduxsub_tmp->urbOut) { - if (usbduxsub_tmp->ao_cmd_running) { - usbduxsub_tmp->ao_cmd_running = 0; - usbduxsub_unlink_OutURBs(usbduxsub_tmp); - } - for (i = 0; i < usbduxsub_tmp->numOfOutBuffers; i++) { - kfree(usbduxsub_tmp->urbOut[i]->transfer_buffer); - usbduxsub_tmp->urbOut[i]->transfer_buffer = NULL; - if (usbduxsub_tmp->urbOut[i]) { - usb_kill_urb(usbduxsub_tmp->urbOut[i]); - usb_free_urb(usbduxsub_tmp->urbOut[i]); - usbduxsub_tmp->urbOut[i] = NULL; - } - } - kfree(usbduxsub_tmp->urbOut); - usbduxsub_tmp->urbOut = NULL; - } - if (usbduxsub_tmp->urbPwm) { - if (usbduxsub_tmp->pwm_cmd_running) { - usbduxsub_tmp->pwm_cmd_running = 0; - usbduxsub_unlink_PwmURBs(usbduxsub_tmp); - } - kfree(usbduxsub_tmp->urbPwm->transfer_buffer); - usbduxsub_tmp->urbPwm->transfer_buffer = NULL; - usb_kill_urb(usbduxsub_tmp->urbPwm); - usb_free_urb(usbduxsub_tmp->urbPwm); - usbduxsub_tmp->urbPwm = NULL; + /* we need a malloc'ed buffer for usb_control_msg() */ + tmp = kmalloc(1, GFP_KERNEL); + if (!tmp) { + kfree(buf); + return -ENOMEM; } - kfree(usbduxsub_tmp->inBuffer); - usbduxsub_tmp->inBuffer = NULL; - kfree(usbduxsub_tmp->insnBuffer); - usbduxsub_tmp->insnBuffer = NULL; - kfree(usbduxsub_tmp->outBuffer); - usbduxsub_tmp->outBuffer = NULL; - kfree(usbduxsub_tmp->dac_commands); - usbduxsub_tmp->dac_commands = NULL; - kfree(usbduxsub_tmp->dux_commands); - usbduxsub_tmp->dux_commands = NULL; - usbduxsub_tmp->ai_cmd_running = 0; - usbduxsub_tmp->ao_cmd_running = 0; - usbduxsub_tmp->pwm_cmd_running = 0; -} - -static void usbdux_firmware_request_complete_handler(const struct firmware *fw, - void *context) -{ - struct usbduxsub *usbduxsub_tmp = context; - struct usb_device *usbdev = usbduxsub_tmp->usbdev; - int ret; - if (fw == NULL) { - dev_err(&usbdev->dev, - "Firmware complete handler without firmware!\n"); - return; + /* stop the current firmware on the device */ + *tmp = 1; /* 7f92 to one */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUX_FIRMWARE_CMD, + VENDOR_DIR_OUT, + USBDUX_CPU_CS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "can not stop firmware\n"); + goto done; } - /* - * we need to upload the firmware here because fw will be - * freed once we've left this function - */ - ret = firmwareUpload(usbduxsub_tmp, fw->data, fw->size); + /* upload the new firmware to the device */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUX_FIRMWARE_CMD, + VENDOR_DIR_OUT, + 0, 0x0000, + buf, size, + BULK_TIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "firmware upload failed\n"); + goto done; + } + + /* start the new firmware on the device */ + *tmp = 0; /* 7f92 to zero */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUX_FIRMWARE_CMD, + VENDOR_DIR_OUT, + USBDUX_CPU_CS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) + dev_err(dev->class_dev, "can not start firmware\n"); - if (ret) { - dev_err(&usbdev->dev, - "Could not upload firmware (err=%d)\n", ret); - goto out; - } - comedi_usb_auto_config(usbdev, BOARDNAME); - out: - release_firmware(fw); +done: + kfree(tmp); + kfree(buf); + return ret; } -/* allocate memory for the urbs and initialise them */ -static int usbduxsub_probe(struct usb_interface *uinterf, - const struct usb_device_id *id) +static int usbdux_alloc_usb_buffers(struct comedi_device *dev) { - struct usb_device *udev = interface_to_usbdev(uinterf); - struct device *dev = &uinterf->dev; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv = dev->private; + struct urb *urb; int i; - int index; - int ret; - dev_dbg(dev, "comedi_: usbdux_: " - "finding a free structure for the usb-device\n"); - - down(&start_stop_sem); - /* look for a free place in the usbdux array */ - index = -1; - for (i = 0; i < NUMUSBDUX; i++) { - if (!(usbduxsub[i].probed)) { - index = i; - break; - } - } - - /* no more space */ - if (index == -1) { - dev_err(dev, "Too many usbdux-devices connected.\n"); - up(&start_stop_sem); - return -EMFILE; - } - dev_dbg(dev, "comedi_: usbdux: " - "usbduxsub[%d] is ready to connect to comedi.\n", index); - - sema_init(&(usbduxsub[index].sem), 1); - /* save a pointer to the usb device */ - usbduxsub[index].usbdev = udev; - - /* 2.6: save the interface itself */ - usbduxsub[index].interface = uinterf; - /* get the interface number from the interface */ - usbduxsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber; - /* hand the private data over to the usb subsystem */ - /* will be needed for disconnect */ - usb_set_intfdata(uinterf, &(usbduxsub[index])); - - dev_dbg(dev, "comedi_: usbdux: ifnum=%d\n", usbduxsub[index].ifnum); - - /* test if it is high speed (USB 2.0) */ - usbduxsub[index].high_speed = - (usbduxsub[index].usbdev->speed == USB_SPEED_HIGH); - - /* create space for the commands of the DA converter */ - usbduxsub[index].dac_commands = kzalloc(NUMOUTCHANNELS, GFP_KERNEL); - if (!usbduxsub[index].dac_commands) { - dev_err(dev, "comedi_: usbdux: " - "error alloc space for dac commands\n"); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space for the commands going to the usb device */ - usbduxsub[index].dux_commands = kzalloc(SIZEOFDUXBUFFER, GFP_KERNEL); - if (!usbduxsub[index].dux_commands) { - dev_err(dev, "comedi_: usbdux: " - "error alloc space for dux commands\n"); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space for the in buffer and set it to zero */ - usbduxsub[index].inBuffer = kzalloc(SIZEINBUF, GFP_KERNEL); - if (!(usbduxsub[index].inBuffer)) { - dev_err(dev, "comedi_: usbdux: " - "could not alloc space for inBuffer\n"); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + 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(void *), + GFP_KERNEL); + devpriv->ao_urbs = kcalloc(devpriv->n_ao_urbs, sizeof(void *), + GFP_KERNEL); + if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf || + !devpriv->ai_urbs || !devpriv->ao_urbs) return -ENOMEM; - } - /* create space of the instruction buffer */ - usbduxsub[index].insnBuffer = kzalloc(SIZEINSNBUF, GFP_KERNEL); - if (!(usbduxsub[index].insnBuffer)) { - dev_err(dev, "comedi_: usbdux: " - "could not alloc space for insnBuffer\n"); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* create space for the outbuffer */ - usbduxsub[index].outBuffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); - if (!(usbduxsub[index].outBuffer)) { - dev_err(dev, "comedi_: usbdux: " - "could not alloc space for outBuffer\n"); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - /* setting to alternate setting 3: enabling iso ep and bulk ep. */ - i = usb_set_interface(usbduxsub[index].usbdev, - usbduxsub[index].ifnum, 3); - if (i < 0) { - dev_err(dev, "comedi_: usbdux%d: " - "could not set alternate setting 3 in high speed.\n", - index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENODEV; - } - if (usbduxsub[index].high_speed) - usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSHIGH; - else - usbduxsub[index].numOfInBuffers = NUMOFINBUFFERSFULL; - - usbduxsub[index].urbIn = - kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfInBuffers, - GFP_KERNEL); - if (!(usbduxsub[index].urbIn)) { - dev_err(dev, "comedi_: usbdux: Could not alloc. urbIn array\n"); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - for (i = 0; i < usbduxsub[index].numOfInBuffers; i++) { + + for (i = 0; i < devpriv->n_ai_urbs; i++) { /* one frame: 1ms */ - usbduxsub[index].urbIn[i] = usb_alloc_urb(1, GFP_KERNEL); - if (usbduxsub[index].urbIn[i] == NULL) { - dev_err(dev, "comedi_: usbdux%d: " - "Could not alloc. urb(%d)\n", index, i); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + urb = usb_alloc_urb(1, GFP_KERNEL); + if (!urb) return -ENOMEM; - } - usbduxsub[index].urbIn[i]->dev = usbduxsub[index].usbdev; - /* will be filled later with a pointer to the comedi-device */ - /* and ONLY then the urb should be submitted */ - usbduxsub[index].urbIn[i]->context = NULL; - usbduxsub[index].urbIn[i]->pipe = - usb_rcvisocpipe(usbduxsub[index].usbdev, ISOINEP); - usbduxsub[index].urbIn[i]->transfer_flags = URB_ISO_ASAP; - usbduxsub[index].urbIn[i]->transfer_buffer = - kzalloc(SIZEINBUF, GFP_KERNEL); - if (!(usbduxsub[index].urbIn[i]->transfer_buffer)) { - dev_err(dev, "comedi_: usbdux%d: " - "could not alloc. transb.\n", index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + devpriv->ai_urbs[i] = urb; + + urb->dev = usb; + urb->context = dev; + urb->pipe = usb_rcvisocpipe(usb, 6); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); + if (!urb->transfer_buffer) return -ENOMEM; - } - usbduxsub[index].urbIn[i]->complete = usbduxsub_ai_IsocIrq; - usbduxsub[index].urbIn[i]->number_of_packets = 1; - usbduxsub[index].urbIn[i]->transfer_buffer_length = SIZEINBUF; - usbduxsub[index].urbIn[i]->iso_frame_desc[0].offset = 0; - usbduxsub[index].urbIn[i]->iso_frame_desc[0].length = SIZEINBUF; - } - /* out */ - if (usbduxsub[index].high_speed) - usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSHIGH; - else - usbduxsub[index].numOfOutBuffers = NUMOFOUTBUFFERSFULL; - - usbduxsub[index].urbOut = - kzalloc(sizeof(struct urb *) * usbduxsub[index].numOfOutBuffers, - GFP_KERNEL); - if (!(usbduxsub[index].urbOut)) { - dev_err(dev, "comedi_: usbdux: " - "Could not alloc. urbOut array\n"); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; + urb->complete = usbduxsub_ai_isoc_irq; + urb->number_of_packets = 1; + urb->transfer_buffer_length = SIZEINBUF; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEINBUF; } - for (i = 0; i < usbduxsub[index].numOfOutBuffers; i++) { + + for (i = 0; i < devpriv->n_ao_urbs; i++) { /* one frame: 1ms */ - usbduxsub[index].urbOut[i] = usb_alloc_urb(1, GFP_KERNEL); - if (usbduxsub[index].urbOut[i] == NULL) { - dev_err(dev, "comedi_: usbdux%d: " - "Could not alloc. urb(%d)\n", index, i); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + urb = usb_alloc_urb(1, GFP_KERNEL); + if (!urb) return -ENOMEM; - } - usbduxsub[index].urbOut[i]->dev = usbduxsub[index].usbdev; - /* will be filled later with a pointer to the comedi-device */ - /* and ONLY then the urb should be submitted */ - usbduxsub[index].urbOut[i]->context = NULL; - usbduxsub[index].urbOut[i]->pipe = - usb_sndisocpipe(usbduxsub[index].usbdev, ISOOUTEP); - usbduxsub[index].urbOut[i]->transfer_flags = URB_ISO_ASAP; - usbduxsub[index].urbOut[i]->transfer_buffer = - kzalloc(SIZEOUTBUF, GFP_KERNEL); - if (!(usbduxsub[index].urbOut[i]->transfer_buffer)) { - dev_err(dev, "comedi_: usbdux%d: " - "could not alloc. transb.\n", index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + devpriv->ao_urbs[i] = urb; + + urb->dev = usb; + urb->context = dev; + urb->pipe = usb_sndisocpipe(usb, 2); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); + if (!urb->transfer_buffer) return -ENOMEM; - } - usbduxsub[index].urbOut[i]->complete = usbduxsub_ao_IsocIrq; - usbduxsub[index].urbOut[i]->number_of_packets = 1; - usbduxsub[index].urbOut[i]->transfer_buffer_length = SIZEOUTBUF; - usbduxsub[index].urbOut[i]->iso_frame_desc[0].offset = 0; - usbduxsub[index].urbOut[i]->iso_frame_desc[0].length = - SIZEOUTBUF; - if (usbduxsub[index].high_speed) { - /* uframes */ - usbduxsub[index].urbOut[i]->interval = 8; - } else { - /* frames */ - usbduxsub[index].urbOut[i]->interval = 1; - } + + urb->complete = usbduxsub_ao_isoc_irq; + urb->number_of_packets = 1; + urb->transfer_buffer_length = SIZEOUTBUF; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEOUTBUF; + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ } /* pwm */ - if (usbduxsub[index].high_speed) { - /* max bulk ep size in high speed */ - usbduxsub[index].sizePwmBuf = 512; - usbduxsub[index].urbPwm = usb_alloc_urb(0, GFP_KERNEL); - if (usbduxsub[index].urbPwm == NULL) { - dev_err(dev, "comedi_: usbdux%d: " - "Could not alloc. pwm urb\n", index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); - return -ENOMEM; - } - usbduxsub[index].urbPwm->transfer_buffer = - kzalloc(usbduxsub[index].sizePwmBuf, GFP_KERNEL); - if (!(usbduxsub[index].urbPwm->transfer_buffer)) { - dev_err(dev, "comedi_: usbdux%d: " - "could not alloc. transb. for pwm\n", index); - tidy_up(&(usbduxsub[index])); - up(&start_stop_sem); + if (devpriv->pwm_buf_sz) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) return -ENOMEM; - } - } else { - usbduxsub[index].urbPwm = NULL; - usbduxsub[index].sizePwmBuf = 0; - } - - usbduxsub[index].ai_cmd_running = 0; - usbduxsub[index].ao_cmd_running = 0; - usbduxsub[index].pwm_cmd_running = 0; - - /* we've reached the bottom of the function */ - usbduxsub[index].probed = 1; - up(&start_stop_sem); + devpriv->pwm_urb = urb; - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, - "usbdux_firmware.bin", - &udev->dev, - GFP_KERNEL, - usbduxsub + index, - usbdux_firmware_request_complete_handler); - - if (ret) { - dev_err(dev, "Could not load firmware (err=%d)\n", ret); - return ret; + /* max bulk ep size in high speed */ + urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz, + GFP_KERNEL); + if (!urb->transfer_buffer) + return -ENOMEM; } - dev_info(dev, "comedi_: usbdux%d " - "has been successfully initialised.\n", index); - /* success */ return 0; } -static void usbduxsub_disconnect(struct usb_interface *intf) +static void usbdux_free_usb_buffers(struct comedi_device *dev) { - struct usbduxsub *usbduxsub_tmp = usb_get_intfdata(intf); - struct usb_device *udev = interface_to_usbdev(intf); + struct usbdux_private *devpriv = dev->private; + struct urb *urb; + int i; - if (!usbduxsub_tmp) { - dev_err(&intf->dev, - "comedi_: disconnect called with null pointer.\n"); - return; - } - if (usbduxsub_tmp->usbdev != udev) { - dev_err(&intf->dev, "comedi_: BUG! called with wrong ptr!!!\n"); - return; + urb = devpriv->pwm_urb; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + if (devpriv->ao_urbs) { + for (i = 0; i < devpriv->n_ao_urbs; i++) { + urb = devpriv->ao_urbs[i]; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } + kfree(devpriv->ao_urbs); + } + if (devpriv->ai_urbs) { + for (i = 0; i < devpriv->n_ai_urbs; i++) { + urb = devpriv->ai_urbs[i]; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } + kfree(devpriv->ai_urbs); } - comedi_usb_auto_unconfig(udev); - down(&start_stop_sem); - down(&usbduxsub_tmp->sem); - tidy_up(usbduxsub_tmp); - up(&usbduxsub_tmp->sem); - up(&start_stop_sem); - dev_dbg(&intf->dev, "comedi_: disconnected from the usb\n"); + kfree(devpriv->insn_buf); + kfree(devpriv->in_buf); + kfree(devpriv->dux_commands); } -/* is called when comedi-config is called */ -static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int usbdux_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbdux_private *devpriv; + struct comedi_subdevice *s; int ret; - int index; - int i; - struct usbduxsub *udev; - - struct comedi_subdevice *s = NULL; - dev->private = NULL; - - down(&start_stop_sem); - /* find a valid device which has been detected by the probe function of - * the usb */ - index = -1; - for (i = 0; i < NUMUSBDUX; i++) { - if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) { - index = i; - break; - } - } - - if (index < 0) { - printk(KERN_ERR "comedi%d: usbdux: error: attach failed, no " - "usbdux devs connected to the usb bus.\n", dev->minor); - up(&start_stop_sem); - return -ENODEV; - } - udev = &usbduxsub[index]; - down(&udev->sem); - /* pointer back to the corresponding comedi device */ - udev->comedidev = dev; + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - /* trying to upload the firmware into the chip */ - if (comedi_aux_data(it->options, 0) && - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { - firmwareUpload(udev, comedi_aux_data(it->options, 0), - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); - } + sema_init(&devpriv->sem, 1); - dev->board_name = BOARDNAME; + usb_set_intfdata(intf, devpriv); - /* set number of subdevices */ - if (udev->high_speed) { - /* with pwm */ - dev->n_subdevices = 5; + devpriv->high_speed = (usb->speed == USB_SPEED_HIGH); + if (devpriv->high_speed) { + devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH; + devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH; + devpriv->pwm_buf_sz = 512; } else { - /* without pwm */ - dev->n_subdevices = 4; + devpriv->n_ai_urbs = NUMOFINBUFFERSFULL; + devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL; } - /* allocate space for the subdevices */ - ret = alloc_subdevices(dev, dev->n_subdevices); + ret = usbdux_alloc_usb_buffers(dev); + if (ret) + return ret; + + /* setting to alternate setting 3: enabling iso ep and bulk ep. */ + ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber, + 3); if (ret < 0) { - dev_err(&udev->interface->dev, - "comedi%d: error alloc space for subdev\n", dev->minor); - up(&start_stop_sem); + dev_err(dev->class_dev, + "could not set alternate setting 3 in high speed\n"); return ret; } - dev_info(&udev->interface->dev, - "comedi%d: usb-device %d is attached to comedi.\n", - dev->minor, index); - /* private structure is also simply the usb-structure */ - dev->private = udev; - - /* the first subdevice is the A/D converter */ - s = dev->subdevices + SUBDEV_AD; - /* the URBs get the comedi subdevice */ - /* which is responsible for reading */ - /* this is the subdevice which reads data */ + ret = comedi_load_firmware(dev, &usb->dev, USBDUX_FIRMWARE, + usbdux_firmware_upload, 0); + if (ret < 0) + return ret; + + ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 5 : 4); + if (ret) + return ret; + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; dev->read_subdev = s; - /* the subdevice receives as private structure the */ - /* usb-structure */ - s->private = NULL; - /* analog input */ - s->type = COMEDI_SUBD_AI; - /* readable and ref is to ground */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - /* 8 channels */ - s->n_chan = 8; - /* length of the channellist */ - s->len_chanlist = 8; - /* callback functions */ - s->insn_read = usbdux_ai_insn_read; - s->do_cmdtest = usbdux_ai_cmdtest; - s->do_cmd = usbdux_ai_cmd; - s->cancel = usbdux_ai_cancel; - /* max value from the A/D converter (12bit) */ - s->maxdata = 0xfff; - /* range table to convert to physical units */ - s->range_table = (&range_usbdux_ai_range); - - /* analog out */ - s = dev->subdevices + SUBDEV_DA; - /* analog out */ - s->type = COMEDI_SUBD_AO; - /* backward pointer */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->n_chan = 8; + s->maxdata = 0x0fff; + s->len_chanlist = 8; + s->range_table = &range_usbdux_ai_range; + s->insn_read = usbdux_ai_insn_read; + s->do_cmdtest = usbdux_ai_cmdtest; + s->do_cmd = usbdux_ai_cmd; + s->cancel = usbdux_ai_cancel; + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; dev->write_subdev = s; - /* the subdevice receives as private structure the */ - /* usb-structure */ - s->private = NULL; - /* are writable */ - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; - /* 4 channels */ - s->n_chan = 4; - /* length of the channellist */ - s->len_chanlist = 4; - /* 12 bit resolution */ - s->maxdata = 0x0fff; - /* bipolar range */ - s->range_table = (&range_usbdux_ao_range); - /* callback */ - s->do_cmdtest = usbdux_ao_cmdtest; - s->do_cmd = usbdux_ao_cmd; - s->cancel = usbdux_ao_cancel; - s->insn_read = usbdux_ao_insn_read; - s->insn_write = usbdux_ao_insn_write; - - /* digital I/O */ - s = dev->subdevices + SUBDEV_DIO; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = (&range_digital); - s->insn_bits = usbdux_dio_insn_bits; - s->insn_config = usbdux_dio_insn_config; - /* we don't use it */ - s->private = NULL; - - /* counter */ - s = dev->subdevices + SUBDEV_COUNTER; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = 4; - s->maxdata = 0xFFFF; - s->insn_read = usbdux_counter_read; - s->insn_write = usbdux_counter_write; - s->insn_config = usbdux_counter_config; - - if (udev->high_speed) { - /* timer / pwm */ - s = dev->subdevices + SUBDEV_PWM; - s->type = COMEDI_SUBD_PWM; - s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; - s->n_chan = 8; - /* this defines the max duty cycle resolution */ - s->maxdata = udev->sizePwmBuf; - s->insn_write = usbdux_pwm_write; - s->insn_read = usbdux_pwm_read; - s->insn_config = usbdux_pwm_config; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; + s->n_chan = USBDUX_NUM_AO_CHAN; + s->maxdata = 0x0fff; + s->len_chanlist = s->n_chan; + s->range_table = &range_usbdux_ao_range; + s->do_cmdtest = usbdux_ao_cmdtest; + s->do_cmd = usbdux_ao_cmd; + s->cancel = usbdux_ao_cancel; + s->insn_read = usbdux_ao_insn_read; + s->insn_write = usbdux_ao_insn_write; + + /* Digital I/O subdevice */ + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = usbdux_dio_insn_bits; + s->insn_config = usbdux_dio_insn_config; + + /* Counter subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 4; + s->maxdata = 0xffff; + s->insn_read = usbdux_counter_read; + s->insn_write = usbdux_counter_write; + s->insn_config = usbdux_counter_config; + + if (devpriv->high_speed) { + /* PWM subdevice */ + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; + s->n_chan = 8; + s->maxdata = devpriv->pwm_buf_sz; + s->insn_write = usbdux_pwm_write; + s->insn_config = usbdux_pwm_config; + usbdux_pwm_period(dev, s, PWM_DEFAULT_PERIOD); } - /* finally decide that it's attached */ - udev->attached = 1; - - up(&udev->sem); - - up(&start_stop_sem); - - dev_info(&udev->interface->dev, "comedi%d: attached to usbdux.\n", - dev->minor); return 0; } -static int usbdux_detach(struct comedi_device *dev) +static void usbdux_detach(struct comedi_device *dev) { - struct usbduxsub *usbduxsub_tmp; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usbdux_private *devpriv = dev->private; - if (!dev) { - printk(KERN_ERR - "comedi?: usbdux: detach without dev variable...\n"); - return -EFAULT; - } + usb_set_intfdata(intf, NULL); - usbduxsub_tmp = dev->private; - if (!usbduxsub_tmp) { - printk(KERN_ERR - "comedi?: usbdux: detach without ptr to usbduxsub[]\n"); - return -EFAULT; - } + if (!devpriv) + return; - dev_dbg(&usbduxsub_tmp->interface->dev, "comedi%d: detach usb device\n", - dev->minor); - - down(&usbduxsub_tmp->sem); - /* Don't allow detach to free the private structure */ - /* It's one entry of of usbduxsub[] */ - dev->private = NULL; - usbduxsub_tmp->attached = 0; - usbduxsub_tmp->comedidev = NULL; - dev_dbg(&usbduxsub_tmp->interface->dev, - "comedi%d: detach: successfully removed\n", dev->minor); - up(&usbduxsub_tmp->sem); - return 0; -} + down(&devpriv->sem); -/* main driver struct */ -static struct comedi_driver driver_usbdux = { - .driver_name = "usbdux", - .module = THIS_MODULE, - .attach = usbdux_attach, - .detach = usbdux_detach, -}; + /* force unlink all urbs */ + usbdux_pwm_stop(dev, 1); + usbdux_ao_stop(dev, 1); + usbdux_ai_stop(dev, 1); -/* Table with the USB-devices: just now only testing IDs */ -static const struct usb_device_id usbduxsub_table[] = { - {USB_DEVICE(0x13d8, 0x0001)}, - {USB_DEVICE(0x13d8, 0x0002)}, - {} /* Terminating entry */ -}; + usbdux_free_usb_buffers(dev); -MODULE_DEVICE_TABLE(usb, usbduxsub_table); + up(&devpriv->sem); +} -/* The usbduxsub-driver */ -static struct usb_driver usbduxsub_driver = { - .name = BOARDNAME, - .probe = usbduxsub_probe, - .disconnect = usbduxsub_disconnect, - .id_table = usbduxsub_table, +static struct comedi_driver usbdux_driver = { + .driver_name = "usbdux", + .module = THIS_MODULE, + .auto_attach = usbdux_auto_attach, + .detach = usbdux_detach, }; -/* Can't use the nice macro as I have also to initialise the USB */ -/* subsystem: */ -/* registering the usb-system _and_ the comedi-driver */ -static int __init init_usbdux(void) +static int usbdux_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) { - printk(KERN_INFO KBUILD_MODNAME ": " - DRIVER_VERSION ":" DRIVER_DESC "\n"); - usb_register(&usbduxsub_driver); - comedi_driver_register(&driver_usbdux); - return 0; + return comedi_usb_auto_config(intf, &usbdux_driver, 0); } -/* deregistering the comedi driver and the usb-subsystem */ -static void __exit exit_usbdux(void) -{ - comedi_driver_unregister(&driver_usbdux); - usb_deregister(&usbduxsub_driver); -} +static const struct usb_device_id usbdux_usb_table[] = { + { USB_DEVICE(0x13d8, 0x0001) }, + { USB_DEVICE(0x13d8, 0x0002) }, + { } +}; +MODULE_DEVICE_TABLE(usb, usbdux_usb_table); -module_init(init_usbdux); -module_exit(exit_usbdux); +static struct usb_driver usbdux_usb_driver = { + .name = "usbdux", + .probe = usbdux_usb_probe, + .disconnect = comedi_usb_auto_unconfig, + .id_table = usbdux_usb_table, +}; +module_comedi_usb_driver(usbdux_driver, usbdux_usb_driver); -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com"); +MODULE_DESCRIPTION("Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(USBDUX_FIRMWARE); diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 2a8e725b785..85f9dcf5940 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* @@ -37,10 +33,10 @@ * udev coldplug problem */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/kernel.h> -#include <linux/firmware.h> #include <linux/module.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/input.h> #include <linux/usb.h> @@ -49,11 +45,6 @@ #include "comedi_fc.h" #include "../comedidev.h" -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com" -#define DRIVER_DESC "USB-DUXfast, BerndPorr@f2s.com" -#define BOARDNAME "usbduxfast" - /* * timeout for the USB-transfer */ @@ -62,6 +53,8 @@ /* * constants for "firmware" upload and download */ +#define FIRMWARE "usbduxfast_firmware.bin" +#define FIRMWARE_MAX_LEN 0x2000 #define USBDUXFASTSUB_FIRMWARE 0xA0 #define VENDOR_DIR_IN 0xC0 #define VENDOR_DIR_OUT 0x40 @@ -114,7 +107,7 @@ /* * size of the buffer for the dux commands in bytes */ -#define SIZEOFDUXBUFFER 256 +#define SIZEOFDUXBUF 256 /* * number of in-URBs which receive the data: min=5 @@ -122,21 +115,6 @@ #define NUMOFINBUFFERSHIGH 10 /* - * total number of usbduxfast devices - */ -#define NUMUSBDUXFAST 16 - -/* - * number of subdevices - */ -#define N_SUBDEVICES 1 - -/* - * analogue in subdevice - */ -#define SUBDEV_AD 0 - -/* * min delay steps for more than one channel * basically when the mux gives up ;-) * @@ -159,7 +137,10 @@ * comedi constants */ static const struct comedi_lrange range_usbduxfast_ai_range = { - 2, {BIP_RANGE(0.75), BIP_RANGE(0.5)} + 2, { + BIP_RANGE(0.75), + BIP_RANGE(0.5) + } }; /* @@ -168,142 +149,82 @@ static const struct comedi_lrange range_usbduxfast_ai_range = { * this is the structure which holds all the data of this driver * one sub device just now: A/D */ -struct usbduxfastsub_s { - int attached; /* is attached? */ - int probed; /* is it associated with a subdevice? */ - struct usb_device *usbdev; /* pointer to the usb-device */ - struct urb *urbIn; /* BULK-transfer handling: urb */ - int8_t *transfer_buffer; - int16_t *insnBuffer; /* input buffer for single insn */ - int ifnum; /* interface number */ - struct usb_interface *interface; /* interface structure */ - /* comedi device for the interrupt context */ - struct comedi_device *comedidev; +struct usbduxfast_private { + struct urb *urb; /* BULK-transfer handling: urb */ + uint8_t *duxbuf; + int8_t *inbuf; short int ai_cmd_running; /* asynchronous command is running */ - short int ai_continous; /* continous acquisition */ long int ai_sample_count; /* number of samples to acquire */ - uint8_t *dux_commands; /* commands */ int ignore; /* counter which ignores the first buffers */ struct semaphore sem; }; /* - * The pointer to the private usb-data of the driver - * is also the private data for the comedi-device. - * This has to be global as the usb subsystem needs - * global variables. The other reason is that this - * structure must be there _before_ any comedi - * command is issued. The usb subsystem must be - * initialised before comedi can access it. - */ -static struct usbduxfastsub_s usbduxfastsub[NUMUSBDUXFAST]; - -static DEFINE_SEMAPHORE(start_stop_sem); - -/* * bulk transfers to usbduxfast */ #define SENDADCOMMANDS 0 #define SENDINITEP6 1 -static int send_dux_commands(struct usbduxfastsub_s *udfs, int cmd_type) +static int usbduxfast_send_cmd(struct comedi_device *dev, int cmd_type) { - int tmp, nsent; - - udfs->dux_commands[0] = cmd_type; - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: dux_commands: ", - udfs->comedidev->minor); - for (tmp = 0; tmp < SIZEOFDUXBUFFER; tmp++) - printk(" %02x", udfs->dux_commands[tmp]); - printk("\n"); -#endif - - tmp = usb_bulk_msg(udfs->usbdev, - usb_sndbulkpipe(udfs->usbdev, CHANNELLISTEP), - udfs->dux_commands, SIZEOFDUXBUFFER, &nsent, 10000); - if (tmp < 0) - printk(KERN_ERR "comedi%d: could not transmit dux_commands to" - "the usb-device, err=%d\n", udfs->comedidev->minor, tmp); - return tmp; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv = dev->private; + int nsent; + int ret; + + devpriv->duxbuf[0] = cmd_type; + + ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, CHANNELLISTEP), + devpriv->duxbuf, SIZEOFDUXBUF, + &nsent, 10000); + if (ret < 0) + dev_err(dev->class_dev, + "could not transmit command to the usb-device, err=%d\n", + ret); + return ret; } -/* - * Stops the data acquision. - * It should be safe to call this function from any context. - */ -static int usbduxfastsub_unlink_InURBs(struct usbduxfastsub_s *udfs) +static void usbduxfast_cmd_data(struct comedi_device *dev, int index, + uint8_t len, uint8_t op, uint8_t out, + uint8_t log) { - int j = 0; - int err = 0; + struct usbduxfast_private *devpriv = dev->private; - if (udfs && udfs->urbIn) { - udfs->ai_cmd_running = 0; - /* waits until a running transfer is over */ - usb_kill_urb(udfs->urbIn); - j = 0; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi: usbduxfast: unlinked InURB: res=%d\n", j); -#endif - return err; + /* Set the GPIF bytes, the first byte is the command byte */ + devpriv->duxbuf[1 + 0x00 + index] = len; + devpriv->duxbuf[1 + 0x08 + index] = op; + devpriv->duxbuf[1 + 0x10 + index] = out; + devpriv->duxbuf[1 + 0x18 + index] = log; } -/* - * This will stop a running acquisition operation. - * Is called from within this driver from both the - * interrupt context and from comedi. - */ -static int usbduxfast_ai_stop(struct usbduxfastsub_s *udfs, int do_unlink) +static int usbduxfast_ai_stop(struct comedi_device *dev, int do_unlink) { - int ret = 0; - - if (!udfs) { - printk(KERN_ERR "comedi?: usbduxfast_ai_stop: udfs=NULL!\n"); - return -EFAULT; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi: usbduxfast_ai_stop\n"); -#endif + struct usbduxfast_private *devpriv = dev->private; - udfs->ai_cmd_running = 0; + /* stop aquistion */ + devpriv->ai_cmd_running = 0; - if (do_unlink) - /* stop aquistion */ - ret = usbduxfastsub_unlink_InURBs(udfs); + if (do_unlink && devpriv->urb) { + /* kill the running transfer */ + usb_kill_urb(devpriv->urb); + } - return ret; + return 0; } -/* - * This will cancel a running acquisition operation. - * This is called by comedi but never from inside the driver. - */ static int usbduxfast_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - struct usbduxfastsub_s *udfs; + struct usbduxfast_private *devpriv = dev->private; int ret; - /* force unlink of all urbs */ -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi: usbduxfast_ai_cancel\n"); -#endif - udfs = dev->private; - if (!udfs) { - printk(KERN_ERR "comedi: usbduxfast_ai_cancel: udfs=NULL\n"); + if (!devpriv) return -EFAULT; - } - down(&udfs->sem); - if (!udfs->probed) { - up(&udfs->sem); - return -ENODEV; - } - /* unlink */ - ret = usbduxfast_ai_stop(udfs, 1); - up(&udfs->sem); + + down(&devpriv->sem); + ret = usbduxfast_ai_stop(dev, 1); + up(&devpriv->sem); return ret; } @@ -312,36 +233,18 @@ static int usbduxfast_ai_cancel(struct comedi_device *dev, * analogue IN * interrupt service routine */ -static void usbduxfastsub_ai_Irq(struct urb *urb) +static void usbduxfast_ai_interrupt(struct urb *urb) { + struct comedi_device *dev = urb->context; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_async *async = s->async; + struct comedi_cmd *cmd = &async->cmd; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv = dev->private; int n, err; - struct usbduxfastsub_s *udfs; - struct comedi_device *this_comedidev; - struct comedi_subdevice *s; - uint16_t *p; - /* sanity checks - is the urb there? */ - if (!urb) { - printk(KERN_ERR "comedi_: usbduxfast_: ao int-handler called " - "with urb=NULL!\n"); - return; - } - /* the context variable points to the subdevice */ - this_comedidev = urb->context; - if (!this_comedidev) { - printk(KERN_ERR "comedi_: usbduxfast_: urb context is a NULL " - "pointer!\n"); - return; - } - /* the private structure of the subdevice is usbduxfastsub_s */ - udfs = this_comedidev->private; - if (!udfs) { - printk(KERN_ERR "comedi_: usbduxfast_: private of comedi " - "subdev is a NULL pointer!\n"); - return; - } /* are we running a command? */ - if (unlikely(!udfs->ai_cmd_running)) { + if (unlikely(!devpriv->ai_cmd_running)) { /* * not running a command * do not continue execution if no asynchronous command @@ -350,13 +253,6 @@ static void usbduxfastsub_ai_Irq(struct urb *urb) return; } - if (unlikely(!udfs->attached)) { - /* no comedi device there */ - return; - } - /* subdevice which is the AD converter */ - s = this_comedidev->subdevices + SUBDEV_AD; - /* first we test if something unusual has just happened */ switch (urb->status) { case 0: @@ -371,181 +267,93 @@ static void usbduxfastsub_ai_Irq(struct urb *urb) case -ESHUTDOWN: case -ECONNABORTED: /* tell this comedi */ - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(udfs->comedidev, s); + async->events |= COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; + comedi_event(dev, s); /* stop the transfer w/o unlink */ - usbduxfast_ai_stop(udfs, 0); + usbduxfast_ai_stop(dev, 0); return; default: - printk("comedi%d: usbduxfast: non-zero urb status received in " - "ai intr context: %d\n", - udfs->comedidev->minor, urb->status); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(udfs->comedidev, s); - usbduxfast_ai_stop(udfs, 0); + pr_err("non-zero urb status received in ai intr context: %d\n", + urb->status); + async->events |= COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; + comedi_event(dev, s); + usbduxfast_ai_stop(dev, 0); return; } - p = urb->transfer_buffer; - if (!udfs->ignore) { - if (!udfs->ai_continous) { + if (!devpriv->ignore) { + if (cmd->stop_src == TRIG_COUNT) { /* not continuous, fixed number of samples */ n = urb->actual_length / sizeof(uint16_t); - if (unlikely(udfs->ai_sample_count < n)) { - /* - * we have send only a fraction of the bytes - * received - */ + if (unlikely(devpriv->ai_sample_count < n)) { + unsigned int num_bytes; + + /* partial sample received */ + num_bytes = devpriv->ai_sample_count * + sizeof(uint16_t); cfc_write_array_to_buffer(s, urb->transfer_buffer, - udfs->ai_sample_count - * sizeof(uint16_t)); - usbduxfast_ai_stop(udfs, 0); + num_bytes); + usbduxfast_ai_stop(dev, 0); /* tell comedi that the acquistion is over */ - s->async->events |= COMEDI_CB_EOA; - comedi_event(udfs->comedidev, s); + async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); return; } - udfs->ai_sample_count -= n; + devpriv->ai_sample_count -= n; } /* write the full buffer to comedi */ err = cfc_write_array_to_buffer(s, urb->transfer_buffer, urb->actual_length); if (unlikely(err == 0)) { /* buffer overflow */ - usbduxfast_ai_stop(udfs, 0); + usbduxfast_ai_stop(dev, 0); return; } /* tell comedi that data is there */ - comedi_event(udfs->comedidev, s); - + comedi_event(dev, s); } else { /* ignore this packet */ - udfs->ignore--; + devpriv->ignore--; } /* * command is still running * resubmit urb for BULK transfer */ - urb->dev = udfs->usbdev; + urb->dev = usb; urb->status = 0; err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - printk(KERN_ERR "comedi%d: usbduxfast: urb resubm failed: %d", - udfs->comedidev->minor, err); - s->async->events |= COMEDI_CB_EOA; - s->async->events |= COMEDI_CB_ERROR; - comedi_event(udfs->comedidev, s); - usbduxfast_ai_stop(udfs, 0); - } -} - -static int usbduxfastsub_start(struct usbduxfastsub_s *udfs) -{ - int ret; - unsigned char local_transfer_buffer[16]; - - /* 7f92 to zero */ - local_transfer_buffer[0] = 0; - /* bRequest, "Firmware" */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, - VENDOR_DIR_OUT, /* bmRequestType */ - USBDUXFASTSUB_CPUCS, /* Value */ - 0x0000, /* Index */ - /* address of the transfer buffer */ - local_transfer_buffer, - 1, /* Length */ - EZTIMEOUT); /* Timeout */ - if (ret < 0) { - printk("comedi_: usbduxfast_: control msg failed (start)\n"); - return ret; - } - - return 0; -} - -static int usbduxfastsub_stop(struct usbduxfastsub_s *udfs) -{ - int ret; - unsigned char local_transfer_buffer[16]; - - /* 7f92 to one */ - local_transfer_buffer[0] = 1; - /* bRequest, "Firmware" */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, - VENDOR_DIR_OUT, /* bmRequestType */ - USBDUXFASTSUB_CPUCS, /* Value */ - 0x0000, /* Index */ - local_transfer_buffer, 1, /* Length */ - EZTIMEOUT); /* Timeout */ - if (ret < 0) { - printk(KERN_ERR "comedi_: usbduxfast: control msg failed " - "(stop)\n"); - return ret; - } - - return 0; -} - -static int usbduxfastsub_upload(struct usbduxfastsub_s *udfs, - unsigned char *local_transfer_buffer, - unsigned int startAddr, unsigned int len) -{ - int ret; - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi: usbduxfast: uploading %d bytes", len); - printk(KERN_DEBUG " to addr %d, first byte=%d.\n", - startAddr, local_transfer_buffer[0]); -#endif - /* brequest, firmware */ - ret = usb_control_msg(udfs->usbdev, usb_sndctrlpipe(udfs->usbdev, 0), USBDUXFASTSUB_FIRMWARE, - VENDOR_DIR_OUT, /* bmRequestType */ - startAddr, /* value */ - 0x0000, /* index */ - /* our local safe buffer */ - local_transfer_buffer, - len, /* length */ - EZTIMEOUT); /* timeout */ - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: result=%d\n", ret); -#endif - - if (ret < 0) { - printk(KERN_ERR "comedi_: usbduxfast: uppload failed\n"); - return ret; + dev_err(dev->class_dev, + "urb resubm failed: %d", err); + async->events |= COMEDI_CB_EOA; + async->events |= COMEDI_CB_ERROR; + comedi_event(dev, s); + usbduxfast_ai_stop(dev, 0); } - - return 0; } -static int usbduxfastsub_submit_InURBs(struct usbduxfastsub_s *udfs) +static int usbduxfast_submit_urb(struct comedi_device *dev) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv = dev->private; int ret; - if (!udfs) + if (!devpriv) return -EFAULT; - usb_fill_bulk_urb(udfs->urbIn, udfs->usbdev, - usb_rcvbulkpipe(udfs->usbdev, BULKINEP), - udfs->transfer_buffer, - SIZEINBUF, usbduxfastsub_ai_Irq, udfs->comedidev); - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: submitting in-urb: " - "0x%p,0x%p\n", udfs->comedidev->minor, udfs->urbIn->context, - udfs->urbIn->dev); -#endif - ret = usb_submit_urb(udfs->urbIn, GFP_ATOMIC); + usb_fill_bulk_urb(devpriv->urb, usb, usb_rcvbulkpipe(usb, BULKINEP), + devpriv->inbuf, SIZEINBUF, + usbduxfast_ai_interrupt, dev); + + ret = usb_submit_urb(devpriv->urb, GFP_ATOMIC); if (ret) { - printk(KERN_ERR "comedi_: usbduxfast: ai: usb_submit_urb error" - " %d\n", ret); + dev_err(dev->class_dev, "usb_submit_urb error %d\n", ret); return ret; } return 0; @@ -555,127 +363,73 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, stop_mask = 0; + int err = 0; long int steps, tmp; - int minSamplPer; - struct usbduxfastsub_s *udfs = dev->private; + int min_sample_period; - if (!udfs->probed) - return -ENODEV; + /* Step 1 : check if triggers are trivially valid */ -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast_ai_cmdtest\n", dev->minor); - printk(KERN_DEBUG "comedi%d: usbduxfast: convert_arg=%u " - "scan_begin_arg=%u\n", - dev->minor, cmd->convert_arg, cmd->scan_begin_arg); -#endif - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - stop_mask = TRIG_COUNT | TRIG_NONE; - cmd->stop_src &= stop_mask; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_EXT | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually compatible - */ + /* 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); - if (cmd->start_src != TRIG_NOW && - cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_INT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE) - err++; + /* 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++; + err |= -EINVAL; if (err) return 2; - /* step 3: make sure arguments are trivially compatible */ + /* Step 3: check if arguments are trivially valid */ - if (cmd->start_src == TRIG_NOW && cmd->start_arg != 0) { - cmd->start_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); if (!cmd->chanlist_len) - err++; + err |= -EINVAL; - if (cmd->scan_end_arg != cmd->chanlist_len) { - cmd->scan_end_arg = cmd->chanlist_len; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); if (cmd->chanlist_len == 1) - minSamplPer = 1; + min_sample_period = 1; else - minSamplPer = MIN_SAMPLING_PERIOD; + min_sample_period = MIN_SAMPLING_PERIOD; if (cmd->convert_src == TRIG_TIMER) { steps = cmd->convert_arg * 30; - if (steps < (minSamplPer * 1000)) - steps = minSamplPer * 1000; + if (steps < (min_sample_period * 1000)) + steps = min_sample_period * 1000; if (steps > (MAX_SAMPLING_PERIOD * 1000)) steps = MAX_SAMPLING_PERIOD * 1000; /* calc arg again */ tmp = steps / 30; - if (cmd->convert_arg != tmp) { - cmd->convert_arg = tmp; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->convert_arg, tmp); } - if (cmd->scan_begin_src == TRIG_TIMER) - err++; - /* stop source */ switch (cmd->stop_src) { case TRIG_COUNT: - if (!cmd->stop_arg) { - cmd->stop_arg = 1; - err++; - } + err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); break; case TRIG_NONE: - if (cmd->stop_arg != 0) { - cmd->stop_arg = 0; - err++; - } + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); break; /* * TRIG_EXT doesn't care since it doesn't trigger @@ -696,83 +450,54 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, static int usbduxfast_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int trignum) + unsigned int trig_num) { + struct usbduxfast_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; int ret; - struct usbduxfastsub_s *udfs = dev->private; - if (!udfs) + if (!devpriv) return -EFAULT; - down(&udfs->sem); - if (!udfs->probed) { - up(&udfs->sem); - return -ENODEV; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast_ai_inttrig\n", dev->minor); -#endif - - if (trignum != 0) { - printk(KERN_ERR "comedi%d: usbduxfast_ai_inttrig: invalid" - " trignum\n", dev->minor); - up(&udfs->sem); + if (trig_num != cmd->start_arg) return -EINVAL; - } - if (!udfs->ai_cmd_running) { - udfs->ai_cmd_running = 1; - ret = usbduxfastsub_submit_InURBs(udfs); + + down(&devpriv->sem); + + if (!devpriv->ai_cmd_running) { + devpriv->ai_cmd_running = 1; + ret = usbduxfast_submit_urb(dev); if (ret < 0) { - printk(KERN_ERR "comedi%d: usbduxfast_ai_inttrig: " - "urbSubmit: err=%d\n", dev->minor, ret); - udfs->ai_cmd_running = 0; - up(&udfs->sem); + dev_err(dev->class_dev, "urbSubmit: err=%d\n", ret); + devpriv->ai_cmd_running = 0; + up(&devpriv->sem); return ret; } s->async->inttrig = NULL; } else { - printk(KERN_ERR "comedi%d: ai_inttrig but acqu is already" - " running\n", dev->minor); + dev_err(dev->class_dev, "ai is already running\n"); } - up(&udfs->sem); + up(&devpriv->sem); return 1; } -/* - * offsets for the GPIF bytes - * the first byte is the command byte - */ -#define LENBASE (1+0x00) -#define OPBASE (1+0x08) -#define OUTBASE (1+0x10) -#define LOGBASE (1+0x18) - static int usbduxfast_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct usbduxfast_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int chan, gain, rngmask = 0xff; int i, j, ret; - struct usbduxfastsub_s *udfs; int result; long steps, steps_tmp; -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast_ai_cmd\n", dev->minor); -#endif - udfs = dev->private; - if (!udfs) + if (!devpriv) return -EFAULT; - down(&udfs->sem); - if (!udfs->probed) { - up(&udfs->sem); - return -ENODEV; - } - if (udfs->ai_cmd_running) { - printk(KERN_ERR "comedi%d: ai_cmd not possible. Another ai_cmd" - " is running.\n", dev->minor); - up(&udfs->sem); + down(&devpriv->sem); + if (devpriv->ai_cmd_running) { + dev_err(dev->class_dev, "ai_cmd not possible\n"); + up(&devpriv->sem); return -EBUSY; } /* set current channel of the running acquisition to zero */ @@ -782,68 +507,52 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, * ignore the first buffers from the device if there * is an error condition */ - udfs->ignore = PACKETS_TO_IGNORE; - - if (cmd->chanlist_len > 0) { - gain = CR_RANGE(cmd->chanlist[0]); - for (i = 0; i < cmd->chanlist_len; ++i) { - chan = CR_CHAN(cmd->chanlist[i]); - if (chan != i) { - printk(KERN_ERR "comedi%d: cmd is accepting " - "only consecutive channels.\n", - dev->minor); - up(&udfs->sem); - return -EINVAL; - } - if ((gain != CR_RANGE(cmd->chanlist[i])) - && (cmd->chanlist_len > 3)) { - printk(KERN_ERR "comedi%d: the gain must be" - " the same for all channels.\n", - dev->minor); - up(&udfs->sem); - return -EINVAL; - } - if (i >= NUMCHANNELS) { - printk(KERN_ERR "comedi%d: channel list too" - " long\n", dev->minor); - break; - } + devpriv->ignore = PACKETS_TO_IGNORE; + + gain = CR_RANGE(cmd->chanlist[0]); + for (i = 0; i < cmd->chanlist_len; ++i) { + chan = CR_CHAN(cmd->chanlist[i]); + if (chan != i) { + dev_err(dev->class_dev, + "channels are not consecutive\n"); + up(&devpriv->sem); + return -EINVAL; + } + if ((gain != CR_RANGE(cmd->chanlist[i])) + && (cmd->chanlist_len > 3)) { + dev_err(dev->class_dev, + "gain must be the same for all channels\n"); + up(&devpriv->sem); + return -EINVAL; + } + if (i >= NUMCHANNELS) { + dev_err(dev->class_dev, "chanlist too long\n"); + break; } } steps = 0; - if (cmd->scan_begin_src == TRIG_TIMER) { - printk(KERN_ERR "comedi%d: usbduxfast: " - "scan_begin_src==TRIG_TIMER not valid.\n", dev->minor); - up(&udfs->sem); - return -EINVAL; - } if (cmd->convert_src == TRIG_TIMER) steps = (cmd->convert_arg * 30) / 1000; if ((steps < MIN_SAMPLING_PERIOD) && (cmd->chanlist_len != 1)) { - printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: steps=%ld, " - "scan_begin_arg=%d. Not properly tested by cmdtest?\n", - dev->minor, steps, cmd->scan_begin_arg); - up(&udfs->sem); + dev_err(dev->class_dev, + "steps=%ld, scan_begin_arg=%d. Not properly tested by cmdtest?\n", + steps, cmd->scan_begin_arg); + up(&devpriv->sem); return -EINVAL; } if (steps > MAX_SAMPLING_PERIOD) { - printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: sampling rate " - "too low.\n", dev->minor); - up(&udfs->sem); + dev_err(dev->class_dev, "sampling rate too low\n"); + up(&devpriv->sem); return -EINVAL; } if ((cmd->start_src == TRIG_EXT) && (cmd->chanlist_len != 1) && (cmd->chanlist_len != 16)) { - printk(KERN_ERR "comedi%d: usbduxfast: ai_cmd: TRIG_EXT only" - " with 1 or 16 channels possible.\n", dev->minor); - up(&udfs->sem); + dev_err(dev->class_dev, + "TRIG_EXT only with 1 or 16 channels possible\n"); + up(&devpriv->sem); return -EINVAL; } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: steps=%ld, convert_arg=%u\n", - dev->minor, steps, cmd->convert_arg); -#endif switch (cmd->chanlist_len) { case 1: @@ -864,17 +573,11 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, /* we loop here until ready has been set */ if (cmd->start_src == TRIG_EXT) { /* branch back to state 0 */ - udfs->dux_commands[LENBASE + 0] = 0x01; /* deceision state w/o data */ - udfs->dux_commands[OPBASE + 0] = 0x01; - udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask; /* RDY0 = 0 */ - udfs->dux_commands[LOGBASE + 0] = 0x00; + usbduxfast_cmd_data(dev, 0, 0x01, 0x01, rngmask, 0x00); } else { /* we just proceed to state 1 */ - udfs->dux_commands[LENBASE + 0] = 1; - udfs->dux_commands[OPBASE + 0] = 0; - udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; + usbduxfast_cmd_data(dev, 0, 0x01, 0x00, rngmask, 0x00); } if (steps < MIN_SAMPLING_PERIOD) { @@ -887,33 +590,25 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ /* branch back to state 1 */ - udfs->dux_commands[LENBASE + 1] = 0x89; /* deceision state with data */ - udfs->dux_commands[OPBASE + 1] = 0x03; - udfs->dux_commands[OUTBASE + 1] = - 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 1] = 0xFF; + usbduxfast_cmd_data(dev, 1, + 0x89, 0x03, rngmask, 0xff); } else { /* * we loop through two states: data and delay * max rate is 15MHz */ - udfs->dux_commands[LENBASE + 1] = steps - 1; /* data */ - udfs->dux_commands[OPBASE + 1] = 0x02; - udfs->dux_commands[OUTBASE + 1] = - 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 1] = 0; + usbduxfast_cmd_data(dev, 1, steps - 1, + 0x02, rngmask, 0x00); + /* branch back to state 1 */ - udfs->dux_commands[LENBASE + 2] = 0x09; /* deceision state w/o data */ - udfs->dux_commands[OPBASE + 2] = 0x01; - udfs->dux_commands[OUTBASE + 2] = - 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 2] = 0xFF; + usbduxfast_cmd_data(dev, 2, + 0x09, 0x01, rngmask, 0xff); } } else { /* @@ -925,26 +620,20 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, steps = steps - 1; /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 1] = steps / 2; - udfs->dux_commands[OPBASE + 1] = 0; - udfs->dux_commands[OUTBASE + 1] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 1] = 0; + usbduxfast_cmd_data(dev, 1, + steps / 2, 0x00, rngmask, 0x00); /* and the second part */ - udfs->dux_commands[LENBASE + 2] = steps - steps / 2; - udfs->dux_commands[OPBASE + 2] = 0; - udfs->dux_commands[OUTBASE + 2] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 2] = 0; + usbduxfast_cmd_data(dev, 2, steps - steps / 2, + 0x00, rngmask, 0x00); /* get the data and branch back */ /* branch back to state 1 */ - udfs->dux_commands[LENBASE + 3] = 0x09; /* deceision state w data */ - udfs->dux_commands[OPBASE + 3] = 0x03; - udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 3] = 0xFF; + usbduxfast_cmd_data(dev, 3, + 0x09, 0x03, rngmask, 0xff); } break; @@ -959,11 +648,8 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, else rngmask = 0xff; - udfs->dux_commands[LENBASE + 0] = 1; /* data */ - udfs->dux_commands[OPBASE + 0] = 0x02; - udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; + usbduxfast_cmd_data(dev, 0, 0x01, 0x02, rngmask, 0x00); /* we have 1 state with duration 1: state 0 */ steps_tmp = steps - 1; @@ -974,23 +660,16 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, rngmask = 0xff; /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 1] = steps_tmp / 2; - udfs->dux_commands[OPBASE + 1] = 0; /* count */ - udfs->dux_commands[OUTBASE + 1] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 1] = 0; + usbduxfast_cmd_data(dev, 1, steps_tmp / 2, + 0x00, 0xfe & rngmask, 0x00); /* and the second part */ - udfs->dux_commands[LENBASE + 2] = steps_tmp - steps_tmp / 2; - udfs->dux_commands[OPBASE + 2] = 0; - udfs->dux_commands[OUTBASE + 2] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 2] = 0; + usbduxfast_cmd_data(dev, 2, steps_tmp - steps_tmp / 2, + 0x00, rngmask, 0x00); - udfs->dux_commands[LENBASE + 3] = 1; /* data */ - udfs->dux_commands[OPBASE + 3] = 0x02; - udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 3] = 0; + usbduxfast_cmd_data(dev, 3, 0x01, 0x02, rngmask, 0x00); /* * we have 2 states with duration 1: step 6 and @@ -1004,22 +683,15 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, rngmask = 0xff; /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 4] = steps_tmp / 2; - udfs->dux_commands[OPBASE + 4] = 0; /* reset */ - udfs->dux_commands[OUTBASE + 4] = (0xFF - 0x02) & rngmask; - udfs->dux_commands[LOGBASE + 4] = 0; + usbduxfast_cmd_data(dev, 4, steps_tmp / 2, + 0x00, (0xff - 0x02) & rngmask, 0x00); /* and the second part */ - udfs->dux_commands[LENBASE + 5] = steps_tmp - steps_tmp / 2; - udfs->dux_commands[OPBASE + 5] = 0; - udfs->dux_commands[OUTBASE + 5] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 5] = 0; - - udfs->dux_commands[LENBASE + 6] = 1; - udfs->dux_commands[OPBASE + 6] = 0; - udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 6] = 0; + usbduxfast_cmd_data(dev, 5, steps_tmp - steps_tmp / 2, + 0x00, rngmask, 0x00); + + usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00); break; case 3: @@ -1027,6 +699,8 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, * three channels */ for (j = 0; j < 1; j++) { + int index = j * 2; + if (CR_RANGE(cmd->chanlist[j]) > 0) rngmask = 0xff - 0x04; else @@ -1035,12 +709,10 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, * commit data to the FIFO and do the first part * of the delay */ - udfs->dux_commands[LENBASE + j * 2] = steps / 2; /* data */ - udfs->dux_commands[OPBASE + j * 2] = 0x02; /* no change */ - udfs->dux_commands[OUTBASE + j * 2] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + j * 2] = 0; + usbduxfast_cmd_data(dev, index, steps / 2, + 0x02, rngmask, 0x00); if (CR_RANGE(cmd->chanlist[j + 1]) > 0) rngmask = 0xff - 0x04; @@ -1048,25 +720,19 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, rngmask = 0xff; /* do the second part of the delay */ - udfs->dux_commands[LENBASE + j * 2 + 1] = - steps - steps / 2; /* no data */ - udfs->dux_commands[OPBASE + j * 2 + 1] = 0; /* count */ - udfs->dux_commands[OUTBASE + j * 2 + 1] = - 0xFE & rngmask; - udfs->dux_commands[LOGBASE + j * 2 + 1] = 0; + usbduxfast_cmd_data(dev, index + 1, steps - steps / 2, + 0x00, 0xfe & rngmask, 0x00); } /* 2 steps with duration 1: the idele step and step 6: */ steps_tmp = steps - 2; /* commit data to the FIFO and do the first part of the delay */ - udfs->dux_commands[LENBASE + 4] = steps_tmp / 2; /* data */ - udfs->dux_commands[OPBASE + 4] = 0x02; - udfs->dux_commands[OUTBASE + 4] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 4] = 0; + usbduxfast_cmd_data(dev, 4, steps_tmp / 2, + 0x02, rngmask, 0x00); if (CR_RANGE(cmd->chanlist[0]) > 0) rngmask = 0xff - 0x04; @@ -1074,17 +740,12 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, rngmask = 0xff; /* do the second part of the delay */ - udfs->dux_commands[LENBASE + 5] = steps_tmp - steps_tmp / 2; /* no data */ - udfs->dux_commands[OPBASE + 5] = 0; /* reset */ - udfs->dux_commands[OUTBASE + 5] = (0xFF - 0x02) & rngmask; - udfs->dux_commands[LOGBASE + 5] = 0; + usbduxfast_cmd_data(dev, 5, steps_tmp - steps_tmp / 2, + 0x00, (0xff - 0x02) & rngmask, 0x00); - udfs->dux_commands[LENBASE + 6] = 1; - udfs->dux_commands[OPBASE + 6] = 0; - udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 6] = 0; + usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00); case 16: if (CR_RANGE(cmd->chanlist[0]) > 0) @@ -1098,115 +759,77 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ /* branch back to state 0 */ - udfs->dux_commands[LENBASE + 0] = 0x01; /* deceision state w/o data */ - udfs->dux_commands[OPBASE + 0] = 0x01; /* reset */ - udfs->dux_commands[OUTBASE + 0] = - (0xFF - 0x02) & rngmask; /* RDY0 = 0 */ - udfs->dux_commands[LOGBASE + 0] = 0x00; + usbduxfast_cmd_data(dev, 0, 0x01, 0x01, + (0xff - 0x02) & rngmask, 0x00); } else { /* * we just proceed to state 1 */ /* 30us reset pulse */ - udfs->dux_commands[LENBASE + 0] = 255; - udfs->dux_commands[OPBASE + 0] = 0; /* reset */ - udfs->dux_commands[OUTBASE + 0] = - (0xFF - 0x02) & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; + usbduxfast_cmd_data(dev, 0, 0xff, 0x00, + (0xff - 0x02) & rngmask, 0x00); } /* commit data to the FIFO */ - udfs->dux_commands[LENBASE + 1] = 1; /* data */ - udfs->dux_commands[OPBASE + 1] = 0x02; - udfs->dux_commands[OUTBASE + 1] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 1] = 0; + usbduxfast_cmd_data(dev, 1, 0x01, 0x02, rngmask, 0x00); /* we have 2 states with duration 1 */ steps = steps - 2; /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 2] = steps / 2; - udfs->dux_commands[OPBASE + 2] = 0; - udfs->dux_commands[OUTBASE + 2] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 2] = 0; + usbduxfast_cmd_data(dev, 2, steps / 2, + 0x00, 0xfe & rngmask, 0x00); /* and the second part */ - udfs->dux_commands[LENBASE + 3] = steps - steps / 2; - udfs->dux_commands[OPBASE + 3] = 0; - udfs->dux_commands[OUTBASE + 3] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 3] = 0; + usbduxfast_cmd_data(dev, 3, steps - steps / 2, + 0x00, rngmask, 0x00); /* branch back to state 1 */ - udfs->dux_commands[LENBASE + 4] = 0x09; /* deceision state w/o data */ - udfs->dux_commands[OPBASE + 4] = 0x01; - udfs->dux_commands[OUTBASE + 4] = 0xFF & rngmask; /* doesn't matter */ - udfs->dux_commands[LOGBASE + 4] = 0xFF; + usbduxfast_cmd_data(dev, 4, 0x09, 0x01, rngmask, 0xff); break; default: - printk(KERN_ERR "comedi %d: unsupported combination of " - "channels\n", dev->minor); - up(&udfs->sem); + dev_err(dev->class_dev, "unsupported combination of channels\n"); + up(&devpriv->sem); return -EFAULT; } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi %d: sending commands to the usb device\n", - dev->minor); -#endif /* 0 means that the AD commands are sent */ - result = send_dux_commands(udfs, SENDADCOMMANDS); + result = usbduxfast_send_cmd(dev, SENDADCOMMANDS); if (result < 0) { - printk(KERN_ERR "comedi%d: adc command could not be submitted." - "Aborting...\n", dev->minor); - up(&udfs->sem); + up(&devpriv->sem); return result; } - if (cmd->stop_src == TRIG_COUNT) { - udfs->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg; - if (udfs->ai_sample_count < 1) { - printk(KERN_ERR "comedi%d: " - "(cmd->stop_arg)*(cmd->scan_end_arg)<1, " - "aborting.\n", dev->minor); - up(&udfs->sem); - return -EFAULT; - } - udfs->ai_continous = 0; - } else { - /* continous acquisition */ - udfs->ai_continous = 1; - udfs->ai_sample_count = 0; - } + + if (cmd->stop_src == TRIG_COUNT) + devpriv->ai_sample_count = cmd->stop_arg * cmd->scan_end_arg; + else /* TRIG_NONE */ + devpriv->ai_sample_count = 0; if ((cmd->start_src == TRIG_NOW) || (cmd->start_src == TRIG_EXT)) { /* enable this acquisition operation */ - udfs->ai_cmd_running = 1; - ret = usbduxfastsub_submit_InURBs(udfs); + devpriv->ai_cmd_running = 1; + ret = usbduxfast_submit_urb(dev); if (ret < 0) { - udfs->ai_cmd_running = 0; + devpriv->ai_cmd_running = 0; /* fixme: unlink here?? */ - up(&udfs->sem); + up(&devpriv->sem); return ret; } s->async->inttrig = NULL; - } else { - /* - * TRIG_INT - * don't enable the acquision operation - * wait for an internal signal - */ + } else { /* TRIG_INT */ s->async->inttrig = usbduxfast_ai_inttrig; } - up(&udfs->sem); + up(&devpriv->sem); return 0; } @@ -1216,610 +839,301 @@ static int usbduxfast_ai_cmd(struct comedi_device *dev, */ static int usbduxfast_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + uint8_t rngmask = range ? (0xff - 0x04) : 0xff; int i, j, n, actual_length; - int chan, range, rngmask; - int err; - struct usbduxfastsub_s *udfs; - - udfs = dev->private; - if (!udfs) { - printk(KERN_ERR "comedi%d: ai_insn_read: no usb dev.\n", - dev->minor); - return -ENODEV; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: ai_insn_read, insn->n=%d, " - "insn->subdev=%d\n", dev->minor, insn->n, insn->subdev); -#endif - down(&udfs->sem); - if (!udfs->probed) { - up(&udfs->sem); - return -ENODEV; - } - if (udfs->ai_cmd_running) { - printk(KERN_ERR "comedi%d: ai_insn_read not possible. Async " - "Command is running.\n", dev->minor); - up(&udfs->sem); + int ret; + + down(&devpriv->sem); + + if (devpriv->ai_cmd_running) { + dev_err(dev->class_dev, + "ai_insn_read not possible, async cmd is running\n"); + up(&devpriv->sem); return -EBUSY; } - /* sample one channel */ - chan = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); - /* set command for the first channel */ - if (range > 0) - rngmask = 0xff - 0x04; - else - rngmask = 0xff; + /* set command for the first channel */ /* commit data to the FIFO */ - udfs->dux_commands[LENBASE + 0] = 1; /* data */ - udfs->dux_commands[OPBASE + 0] = 0x02; - udfs->dux_commands[OUTBASE + 0] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; + usbduxfast_cmd_data(dev, 0, 0x01, 0x02, rngmask, 0x00); /* do the first part of the delay */ - udfs->dux_commands[LENBASE + 1] = 12; - udfs->dux_commands[OPBASE + 1] = 0; - udfs->dux_commands[OUTBASE + 1] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 1] = 0; - - udfs->dux_commands[LENBASE + 2] = 1; - udfs->dux_commands[OPBASE + 2] = 0; - udfs->dux_commands[OUTBASE + 2] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 2] = 0; - - udfs->dux_commands[LENBASE + 3] = 1; - udfs->dux_commands[OPBASE + 3] = 0; - udfs->dux_commands[OUTBASE + 3] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 3] = 0; - - udfs->dux_commands[LENBASE + 4] = 1; - udfs->dux_commands[OPBASE + 4] = 0; - udfs->dux_commands[OUTBASE + 4] = 0xFE & rngmask; - udfs->dux_commands[LOGBASE + 4] = 0; + usbduxfast_cmd_data(dev, 1, 0x0c, 0x00, 0xfe & rngmask, 0x00); + usbduxfast_cmd_data(dev, 2, 0x01, 0x00, 0xfe & rngmask, 0x00); + usbduxfast_cmd_data(dev, 3, 0x01, 0x00, 0xfe & rngmask, 0x00); + usbduxfast_cmd_data(dev, 4, 0x01, 0x00, 0xfe & rngmask, 0x00); /* second part */ - udfs->dux_commands[LENBASE + 5] = 12; - udfs->dux_commands[OPBASE + 5] = 0; - udfs->dux_commands[OUTBASE + 5] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 5] = 0; - - udfs->dux_commands[LENBASE + 6] = 1; - udfs->dux_commands[OPBASE + 6] = 0; - udfs->dux_commands[OUTBASE + 6] = 0xFF & rngmask; - udfs->dux_commands[LOGBASE + 0] = 0; - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi %d: sending commands to the usb device\n", - dev->minor); -#endif - /* 0 means that the AD commands are sent */ - err = send_dux_commands(udfs, SENDADCOMMANDS); - if (err < 0) { - printk(KERN_ERR "comedi%d: adc command could not be submitted." - "Aborting...\n", dev->minor); - up(&udfs->sem); - return err; + usbduxfast_cmd_data(dev, 5, 0x0c, 0x00, rngmask, 0x00); + usbduxfast_cmd_data(dev, 6, 0x01, 0x00, rngmask, 0x00); + + ret = usbduxfast_send_cmd(dev, SENDADCOMMANDS); + if (ret < 0) { + up(&devpriv->sem); + return ret; } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: submitting in-urb: " - "0x%p,0x%p\n", udfs->comedidev->minor, udfs->urbIn->context, - udfs->urbIn->dev); -#endif + for (i = 0; i < PACKETS_TO_IGNORE; i++) { - err = usb_bulk_msg(udfs->usbdev, - usb_rcvbulkpipe(udfs->usbdev, BULKINEP), - udfs->transfer_buffer, SIZEINBUF, + ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, BULKINEP), + devpriv->inbuf, SIZEINBUF, &actual_length, 10000); - if (err < 0) { - printk(KERN_ERR "comedi%d: insn timeout. No data.\n", - dev->minor); - up(&udfs->sem); - return err; + if (ret < 0) { + dev_err(dev->class_dev, "insn timeout, no data\n"); + up(&devpriv->sem); + return ret; } } - /* data points */ + for (i = 0; i < insn->n;) { - err = usb_bulk_msg(udfs->usbdev, - usb_rcvbulkpipe(udfs->usbdev, BULKINEP), - udfs->transfer_buffer, SIZEINBUF, + ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, BULKINEP), + devpriv->inbuf, SIZEINBUF, &actual_length, 10000); - if (err < 0) { - printk(KERN_ERR "comedi%d: insn data error: %d\n", - dev->minor, err); - up(&udfs->sem); - return err; + if (ret < 0) { + dev_err(dev->class_dev, "insn data error: %d\n", ret); + up(&devpriv->sem); + return ret; } n = actual_length / sizeof(uint16_t); if ((n % 16) != 0) { - printk(KERN_ERR "comedi%d: insn data packet " - "corrupted.\n", dev->minor); - up(&udfs->sem); + dev_err(dev->class_dev, "insn data packet corrupted\n"); + up(&devpriv->sem); return -EINVAL; } for (j = chan; (j < n) && (i < insn->n); j = j + 16) { - data[i] = ((uint16_t *) (udfs->transfer_buffer))[j]; + data[i] = ((uint16_t *) (devpriv->inbuf))[j]; i++; } } - up(&udfs->sem); - return i; -} -#define FIRMWARE_MAX_LEN 0x2000 + up(&devpriv->sem); + + return insn->n; +} -static int firmwareUpload(struct usbduxfastsub_s *usbduxfastsub, - const u8 *firmwareBinary, int sizeFirmware) +static int usbduxfast_attach_common(struct comedi_device *dev) { + struct usbduxfast_private *devpriv = dev->private; + struct comedi_subdevice *s; int ret; - uint8_t *fwBuf; - if (!firmwareBinary) - return 0; + down(&devpriv->sem); - if (sizeFirmware > FIRMWARE_MAX_LEN) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: usbduxfast firmware binary it too large for FX2.\n"); - return -ENOMEM; - } - - /* we generate a local buffer for the firmware */ - fwBuf = kmemdup(firmwareBinary, sizeFirmware, GFP_KERNEL); - if (!fwBuf) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: mem alloc for firmware failed\n"); - return -ENOMEM; - } - - ret = usbduxfastsub_stop(usbduxfastsub); - if (ret < 0) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: can not stop firmware\n"); - kfree(fwBuf); + ret = comedi_alloc_subdevices(dev, 1); + if (ret) { + up(&devpriv->sem); return ret; } - ret = usbduxfastsub_upload(usbduxfastsub, fwBuf, 0, sizeFirmware); - if (ret < 0) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: firmware upload failed\n"); - kfree(fwBuf); - return ret; - } - ret = usbduxfastsub_start(usbduxfastsub); - if (ret < 0) { - dev_err(&usbduxfastsub->interface->dev, - "comedi_: can not start firmware\n"); - kfree(fwBuf); - return ret; - } - kfree(fwBuf); + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; + s->n_chan = 16; + s->len_chanlist = 16; + s->insn_read = usbduxfast_ai_insn_read; + s->do_cmdtest = usbduxfast_ai_cmdtest; + s->do_cmd = usbduxfast_ai_cmd; + s->cancel = usbduxfast_ai_cancel; + s->maxdata = 0x1000; + s->range_table = &range_usbduxfast_ai_range; + + up(&devpriv->sem); + return 0; } -static void tidy_up(struct usbduxfastsub_s *udfs) +static int usbduxfast_upload_firmware(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) { -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: tiding up\n"); -#endif - - if (!udfs) - return; - - /* shows the usb subsystem that the driver is down */ - if (udfs->interface) - usb_set_intfdata(udfs->interface, NULL); - - udfs->probed = 0; - - if (udfs->urbIn) { - /* waits until a running transfer is over */ - usb_kill_urb(udfs->urbIn); + struct usb_device *usb = comedi_to_usb_dev(dev); + uint8_t *buf; + unsigned char *tmp; + int ret; - kfree(udfs->transfer_buffer); - udfs->transfer_buffer = NULL; + if (!data) + return 0; - usb_free_urb(udfs->urbIn); - udfs->urbIn = NULL; + if (size > FIRMWARE_MAX_LEN) { + dev_err(dev->class_dev, "firmware binary too large for FX2\n"); + return -ENOMEM; } - kfree(udfs->insnBuffer); - udfs->insnBuffer = NULL; - - kfree(udfs->dux_commands); - udfs->dux_commands = NULL; - - udfs->ai_cmd_running = 0; -} - -static void usbduxfast_firmware_request_complete_handler(const struct firmware - *fw, void *context) -{ - struct usbduxfastsub_s *usbduxfastsub_tmp = context; - struct usb_device *usbdev = usbduxfastsub_tmp->usbdev; - int ret; - - if (fw == NULL) - return; + /* we generate a local buffer for the firmware */ + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; - /* - * we need to upload the firmware here because fw will be - * freed once we've left this function - */ - ret = firmwareUpload(usbduxfastsub_tmp, fw->data, fw->size); + /* we need a malloc'ed buffer for usb_control_msg() */ + tmp = kmalloc(1, GFP_KERNEL); + if (!tmp) { + kfree(buf); + return -ENOMEM; + } - if (ret) { - dev_err(&usbdev->dev, - "Could not upload firmware (err=%d)\n", ret); - goto out; + /* stop the current firmware on the device */ + *tmp = 1; /* 7f92 to one */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXFASTSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXFASTSUB_CPUCS, 0x0000, + tmp, 1, + EZTIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "can not stop firmware\n"); + goto done; } - comedi_usb_auto_config(usbdev, BOARDNAME); - out: - release_firmware(fw); + /* upload the new firmware to the device */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXFASTSUB_FIRMWARE, + VENDOR_DIR_OUT, + 0, 0x0000, + buf, size, + EZTIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "firmware upload failed\n"); + goto done; + } + + /* start the new firmware on the device */ + *tmp = 0; /* 7f92 to zero */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXFASTSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXFASTSUB_CPUCS, 0x0000, + tmp, 1, + EZTIMEOUT); + if (ret < 0) + dev_err(dev->class_dev, "can not start firmware\n"); + +done: + kfree(tmp); + kfree(buf); + return ret; } -/* - * allocate memory for the urbs and initialise them - */ -static int usbduxfastsub_probe(struct usb_interface *uinterf, - const struct usb_device_id *id) +static int usbduxfast_auto_attach(struct comedi_device *dev, + unsigned long context_unused) { - struct usb_device *udev = interface_to_usbdev(uinterf); - int i; - int index; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxfast_private *devpriv; int ret; - if (udev->speed != USB_SPEED_HIGH) { - printk(KERN_ERR "comedi_: usbduxfast_: This driver needs" - "USB 2.0 to operate. Aborting...\n"); + if (usb->speed != USB_SPEED_HIGH) { + dev_err(dev->class_dev, + "This driver needs USB 2.0 to operate. Aborting...\n"); return -ENODEV; } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast_: finding a free structure for " - "the usb-device\n"); -#endif - down(&start_stop_sem); - /* look for a free place in the usbduxfast array */ - index = -1; - for (i = 0; i < NUMUSBDUXFAST; i++) { - if (!usbduxfastsub[i].probed) { - index = i; - break; - } - } - /* no more space */ - if (index == -1) { - printk(KERN_ERR "Too many usbduxfast-devices connected.\n"); - up(&start_stop_sem); - return -EMFILE; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: usbduxfastsub[%d] is ready to " - "connect to comedi.\n", index); -#endif - - sema_init(&(usbduxfastsub[index].sem), 1); - /* save a pointer to the usb device */ - usbduxfastsub[index].usbdev = udev; - - /* save the interface itself */ - usbduxfastsub[index].interface = uinterf; - /* get the interface number from the interface */ - usbduxfastsub[index].ifnum = uinterf->altsetting->desc.bInterfaceNumber; - /* - * hand the private data over to the usb subsystem - * will be needed for disconnect - */ - usb_set_intfdata(uinterf, &(usbduxfastsub[index])); - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: ifnum=%d\n", - usbduxfastsub[index].ifnum); -#endif - /* create space for the commands going to the usb device */ - usbduxfastsub[index].dux_commands = kmalloc(SIZEOFDUXBUFFER, - GFP_KERNEL); - if (!usbduxfastsub[index].dux_commands) { - printk(KERN_ERR "comedi_: usbduxfast: error alloc space for " - "dac commands\n"); - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) return -ENOMEM; - } - /* create space of the instruction buffer */ - usbduxfastsub[index].insnBuffer = kmalloc(SIZEINSNBUF, GFP_KERNEL); - if (!usbduxfastsub[index].insnBuffer) { - printk(KERN_ERR "comedi_: usbduxfast: could not alloc space " - "for insnBuffer\n"); - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + + sema_init(&devpriv->sem, 1); + usb_set_intfdata(intf, devpriv); + + devpriv->duxbuf = kmalloc(SIZEOFDUXBUF, GFP_KERNEL); + if (!devpriv->duxbuf) return -ENOMEM; - } - /* setting to alternate setting 1: enabling bulk ep */ - i = usb_set_interface(usbduxfastsub[index].usbdev, - usbduxfastsub[index].ifnum, 1); - if (i < 0) { - printk(KERN_ERR "comedi_: usbduxfast%d: could not switch to " - "alternate setting 1.\n", index); - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + + ret = usb_set_interface(usb, + intf->altsetting->desc.bInterfaceNumber, 1); + if (ret < 0) { + dev_err(dev->class_dev, + "could not switch to alternate setting 1\n"); return -ENODEV; } - usbduxfastsub[index].urbIn = usb_alloc_urb(0, GFP_KERNEL); - if (!usbduxfastsub[index].urbIn) { - printk(KERN_ERR "comedi_: usbduxfast%d: Could not alloc." - "urb\n", index); - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + + devpriv->urb = usb_alloc_urb(0, GFP_KERNEL); + if (!devpriv->urb) { + dev_err(dev->class_dev, "Could not alloc. urb\n"); return -ENOMEM; } - usbduxfastsub[index].transfer_buffer = kmalloc(SIZEINBUF, GFP_KERNEL); - if (!usbduxfastsub[index].transfer_buffer) { - printk(KERN_ERR "comedi_: usbduxfast%d: could not alloc. " - "transb.\n", index); - tidy_up(&(usbduxfastsub[index])); - up(&start_stop_sem); + + devpriv->inbuf = kmalloc(SIZEINBUF, GFP_KERNEL); + if (!devpriv->inbuf) return -ENOMEM; - } - /* we've reached the bottom of the function */ - usbduxfastsub[index].probed = 1; - up(&start_stop_sem); - - ret = request_firmware_nowait(THIS_MODULE, - FW_ACTION_HOTPLUG, - "usbduxfast_firmware.bin", - &udev->dev, - GFP_KERNEL, - usbduxfastsub + index, - usbduxfast_firmware_request_complete_handler); - if (ret) { - dev_err(&udev->dev, "could not load firmware (err=%d)\n", ret); + ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE, + usbduxfast_upload_firmware, 0); + if (ret) return ret; - } - printk(KERN_INFO "comedi_: usbduxfast%d has been successfully " - "initialized.\n", index); - /* success */ - return 0; + return usbduxfast_attach_common(dev); } -static void usbduxfastsub_disconnect(struct usb_interface *intf) +static void usbduxfast_detach(struct comedi_device *dev) { - struct usbduxfastsub_s *udfs = usb_get_intfdata(intf); - struct usb_device *udev = interface_to_usbdev(intf); + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usbduxfast_private *devpriv = dev->private; - if (!udfs) { - printk(KERN_ERR "comedi_: usbduxfast: disconnect called with " - "null pointer.\n"); + if (!devpriv) return; - } - if (udfs->usbdev != udev) { - printk(KERN_ERR "comedi_: usbduxfast: BUG! called with wrong " - "ptr!!!\n"); - return; - } - comedi_usb_auto_unconfig(udev); + down(&devpriv->sem); - down(&start_stop_sem); - down(&udfs->sem); - tidy_up(udfs); - up(&udfs->sem); - up(&start_stop_sem); - -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi_: usbduxfast: disconnected from the usb\n"); -#endif -} + usb_set_intfdata(intf, NULL); -/* - * is called when comedi-config is called - */ -static int usbduxfast_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - int ret; - int index; - int i; - struct comedi_subdevice *s = NULL; - dev->private = NULL; - - down(&start_stop_sem); - /* - * find a valid device which has been detected by the - * probe function of the usb - */ - index = -1; - for (i = 0; i < NUMUSBDUXFAST; i++) { - if (usbduxfastsub[i].probed && !usbduxfastsub[i].attached) { - index = i; - break; - } - } - - if (index < 0) { - printk(KERN_ERR "comedi%d: usbduxfast: error: attach failed, " - "no usbduxfast devs connected to the usb bus.\n", - dev->minor); - up(&start_stop_sem); - return -ENODEV; - } + if (devpriv->urb) { + /* waits until a running transfer is over */ + usb_kill_urb(devpriv->urb); - down(&(usbduxfastsub[index].sem)); - /* pointer back to the corresponding comedi device */ - usbduxfastsub[index].comedidev = dev; + kfree(devpriv->inbuf); + devpriv->inbuf = NULL; - /* trying to upload the firmware into the chip */ - if (comedi_aux_data(it->options, 0) && - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]) { - firmwareUpload(&usbduxfastsub[index], - comedi_aux_data(it->options, 0), - it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]); + usb_free_urb(devpriv->urb); + devpriv->urb = NULL; } - dev->board_name = BOARDNAME; - - /* set number of subdevices */ - dev->n_subdevices = N_SUBDEVICES; + kfree(devpriv->duxbuf); + devpriv->duxbuf = NULL; - /* allocate space for the subdevices */ - ret = alloc_subdevices(dev, N_SUBDEVICES); - if (ret < 0) { - printk(KERN_ERR "comedi%d: usbduxfast: error alloc space for " - "subdev\n", dev->minor); - up(&(usbduxfastsub[index].sem)); - up(&start_stop_sem); - return ret; - } + devpriv->ai_cmd_running = 0; - printk(KERN_INFO "comedi%d: usbduxfast: usb-device %d is attached to " - "comedi.\n", dev->minor, index); - /* private structure is also simply the usb-structure */ - dev->private = usbduxfastsub + index; - /* the first subdevice is the A/D converter */ - s = dev->subdevices + SUBDEV_AD; - /* - * the URBs get the comedi subdevice which is responsible for reading - * this is the subdevice which reads data - */ - dev->read_subdev = s; - /* the subdevice receives as private structure the usb-structure */ - s->private = NULL; - /* analog input */ - s->type = COMEDI_SUBD_AI; - /* readable and ref is to ground */ - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - /* 16 channels */ - s->n_chan = 16; - /* length of the channellist */ - s->len_chanlist = 16; - /* callback functions */ - s->insn_read = usbduxfast_ai_insn_read; - s->do_cmdtest = usbduxfast_ai_cmdtest; - s->do_cmd = usbduxfast_ai_cmd; - s->cancel = usbduxfast_ai_cancel; - /* max value from the A/D converter (12bit+1 bit for overflow) */ - s->maxdata = 0x1000; - /* range table to convert to physical units */ - s->range_table = &range_usbduxfast_ai_range; - - /* finally decide that it's attached */ - usbduxfastsub[index].attached = 1; - - up(&(usbduxfastsub[index].sem)); - up(&start_stop_sem); - printk(KERN_INFO "comedi%d: successfully attached to usbduxfast.\n", - dev->minor); - - return 0; + up(&devpriv->sem); } -static int usbduxfast_detach(struct comedi_device *dev) -{ - struct usbduxfastsub_s *udfs; - - if (!dev) { - printk(KERN_ERR "comedi?: usbduxfast: detach without dev " - "variable...\n"); - return -EFAULT; - } -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: detach usb device\n", - dev->minor); -#endif - - udfs = dev->private; - if (!udfs) { - printk(KERN_ERR "comedi?: usbduxfast: detach without ptr to " - "usbduxfastsub[]\n"); - return -EFAULT; - } +static struct comedi_driver usbduxfast_driver = { + .driver_name = "usbduxfast", + .module = THIS_MODULE, + .auto_attach = usbduxfast_auto_attach, + .detach = usbduxfast_detach, +}; - down(&udfs->sem); - down(&start_stop_sem); - /* - * Don't allow detach to free the private structure - * It's one entry of of usbduxfastsub[] - */ - dev->private = NULL; - udfs->attached = 0; - udfs->comedidev = NULL; -#ifdef CONFIG_COMEDI_DEBUG - printk(KERN_DEBUG "comedi%d: usbduxfast: detach: successfully " - "removed\n", dev->minor); -#endif - up(&start_stop_sem); - up(&udfs->sem); - return 0; +static int usbduxfast_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return comedi_usb_auto_config(intf, &usbduxfast_driver, 0); } -/* - * main driver struct - */ -static struct comedi_driver driver_usbduxfast = { - .driver_name = "usbduxfast", - .module = THIS_MODULE, - .attach = usbduxfast_attach, - .detach = usbduxfast_detach -}; - -/* - * Table with the USB-devices: just now only testing IDs - */ -static const struct usb_device_id usbduxfastsub_table[] = { +static const struct usb_device_id usbduxfast_usb_table[] = { /* { USB_DEVICE(0x4b4, 0x8613) }, testing */ - {USB_DEVICE(0x13d8, 0x0010)}, /* real ID */ - {USB_DEVICE(0x13d8, 0x0011)}, /* real ID */ - {} /* Terminating entry */ + { USB_DEVICE(0x13d8, 0x0010) }, /* real ID */ + { USB_DEVICE(0x13d8, 0x0011) }, /* real ID */ + { } }; +MODULE_DEVICE_TABLE(usb, usbduxfast_usb_table); -MODULE_DEVICE_TABLE(usb, usbduxfastsub_table); - -/* - * The usbduxfastsub-driver - */ -static struct usb_driver usbduxfastsub_driver = { -#ifdef COMEDI_HAVE_USB_DRIVER_OWNER - .owner = THIS_MODULE, -#endif - .name = BOARDNAME, - .probe = usbduxfastsub_probe, - .disconnect = usbduxfastsub_disconnect, - .id_table = usbduxfastsub_table +static struct usb_driver usbduxfast_usb_driver = { + .name = "usbduxfast", + .probe = usbduxfast_usb_probe, + .disconnect = comedi_usb_auto_unconfig, + .id_table = usbduxfast_usb_table, }; +module_comedi_usb_driver(usbduxfast_driver, usbduxfast_usb_driver); -/* - * Can't use the nice macro as I have also to initialise the USB subsystem: - * registering the usb-system _and_ the comedi-driver - */ -static int __init init_usbduxfast(void) -{ - printk(KERN_INFO - KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); - usb_register(&usbduxfastsub_driver); - comedi_driver_register(&driver_usbduxfast); - return 0; -} - -/* - * deregistering the comedi driver and the usb-subsystem - */ -static void __exit exit_usbduxfast(void) -{ - comedi_driver_unregister(&driver_usbduxfast); - usb_deregister(&usbduxfastsub_driver); -} - -module_init(init_usbduxfast); -module_exit(exit_usbduxfast); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com"); +MODULE_DESCRIPTION("USB-DUXfast, BerndPorr@f2s.com"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(FIRMWARE); diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c new file mode 100644 index 00000000000..ccc3ef7ba55 --- /dev/null +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -0,0 +1,1715 @@ +/* + * usbduxsigma.c + * Copyright (C) 2011 Bernd Porr, Bernd.Porr@f2s.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: usbduxsigma + * Description: University of Stirling USB DAQ & INCITE Technology Limited + * Devices: (ITL) USB-DUX [usbduxsigma] + * Author: Bernd Porr <BerndPorr@f2s.com> + * Updated: 8 Nov 2011 + * Status: testing + */ + +/* + * I must give credit here to Chris Baugher who + * wrote the driver for AT-MIO-16d. I used some parts of this + * driver. I also must give credits to David Brownell + * who supported me with the USB development. + * + * Note: the raw data from the A/D converter is 24 bit big endian + * anything else is little endian to/from the dux board + * + * + * Revision history: + * 0.1: initial version + * 0.2: all basic functions implemented, digital I/O only for one port + * 0.3: proper vendor ID and driver name + * 0.4: fixed D/A voltage range + * 0.5: various bug fixes, health check at startup + * 0.6: corrected wrong input range + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/usb.h> +#include <linux/fcntl.h> +#include <linux/compiler.h> +#include <asm/unaligned.h> + +#include "comedi_fc.h" +#include "../comedidev.h" + +/* timeout for the USB-transfer in ms*/ +#define BULK_TIMEOUT 1000 + +/* constants for "firmware" upload and download */ +#define FIRMWARE "usbduxsigma_firmware.bin" +#define FIRMWARE_MAX_LEN 0x4000 +#define USBDUXSUB_FIRMWARE 0xa0 +#define VENDOR_DIR_IN 0xc0 +#define VENDOR_DIR_OUT 0x40 + +/* internal addresses of the 8051 processor */ +#define USBDUXSUB_CPUCS 0xE600 + +/* 300Hz max frequ under PWM */ +#define MIN_PWM_PERIOD ((long)(1E9/300)) + +/* Default PWM frequency */ +#define PWM_DEFAULT_PERIOD ((long)(1E9/100)) + +/* 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))) + +/* + * Size of the async input-buffer IN BYTES, the DIO state is transmitted + * as the first byte. + */ +#define SIZEINBUF (((NUMCHANNELS+1)*SIZEADIN)) + +/* 16 bytes. */ +#define SIZEINSNBUF 16 + +/* Number of DA channels */ +#define NUMOUTCHANNELS 8 + +/* size of one value for the D/A converter: channel and value */ +#define SIZEDAOUT ((sizeof(uint8_t)+sizeof(uint16_t))) + +/* + * Size of the output-buffer in bytes + * Actually only the first 4 triplets are used but for the + * high speed mode we need to pad it to 8 (microframes). + */ +#define SIZEOUTBUF ((8*SIZEDAOUT)) + +/* + * Size of the buffer for the dux commands: just now max size is determined + * by the analogue out + command byte + panic bytes... + */ +#define SIZEOFDUXBUFFER ((8*SIZEDAOUT+2)) + +/* Number of in-URBs which receive the data: min=2 */ +#define NUMOFINBUFFERSFULL 5 + +/* Number of out-URBs which send the data: min=2 */ +#define NUMOFOUTBUFFERSFULL 5 + +/* Number of in-URBs which receive the data: min=5 */ +/* must have more buffers due to buggy USB ctr */ +#define NUMOFINBUFFERSHIGH 10 + +/* Number of out-URBs which send the data: min=5 */ +/* must have more buffers due to buggy USB ctr */ +#define NUMOFOUTBUFFERSHIGH 10 + +/* number of retries to get the right dux command */ +#define RETRIES 10 + +/* bulk transfer commands to usbduxsigma */ +#define USBBUXSIGMA_AD_CMD 0 +#define USBDUXSIGMA_DA_CMD 1 +#define USBDUXSIGMA_DIO_CFG_CMD 2 +#define USBDUXSIGMA_DIO_BITS_CMD 3 +#define USBDUXSIGMA_SINGLE_AD_CMD 4 +#define USBDUXSIGMA_PWM_ON_CMD 7 +#define USBDUXSIGMA_PWM_OFF_CMD 8 + +static const struct comedi_lrange usbduxsigma_ai_range = { + 1, { + BIP_RANGE(2.65 / 2.0) + } +}; + +struct usbduxsigma_private { + /* actual number of in-buffers */ + int n_ai_urbs; + /* actual number of out-buffers */ + int n_ao_urbs; + /* ISO-transfer handling: buffers */ + struct urb **ai_urbs; + struct urb **ao_urbs; + /* pwm-transfer handling */ + struct urb *pwm_urb; + /* PWM period */ + unsigned int pwm_period; + /* PWM internal delay for the GPIF in the FX2 */ + uint8_t pwm_delay; + /* size of the PWM buffer which holds the bit pattern */ + int pwm_buf_sz; + /* input buffer for the ISO-transfer */ + uint32_t *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; + unsigned pwm_cmd_running:1; + + /* number of samples to acquire */ + int ai_sample_count; + int ao_sample_count; + /* time between samples in units of the timer */ + unsigned int ai_timer; + unsigned int ao_timer; + /* counter between acquisitions */ + unsigned int ai_counter; + unsigned int ao_counter; + /* interval in frames/uframes */ + unsigned int ai_interval; + /* commands */ + uint8_t *dux_commands; + struct semaphore sem; +}; + +static void usbduxsigma_unlink_urbs(struct urb **urbs, int num_urbs) +{ + int i; + + for (i = 0; i < num_urbs; i++) + usb_kill_urb(urbs[i]); +} + +static void usbduxsigma_ai_stop(struct comedi_device *dev, int do_unlink) +{ + struct usbduxsigma_private *devpriv = dev->private; + + if (do_unlink && devpriv->ai_urbs) + usbduxsigma_unlink_urbs(devpriv->ai_urbs, devpriv->n_ai_urbs); + + devpriv->ai_cmd_running = 0; +} + +static int usbduxsigma_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct usbduxsigma_private *devpriv = dev->private; + + down(&devpriv->sem); + /* unlink only if it is really running */ + usbduxsigma_ai_stop(dev, devpriv->ai_cmd_running); + up(&devpriv->sem); + + return 0; +} + +static void usbduxsigma_ai_urb_complete(struct urb *urb) +{ + struct comedi_device *dev = urb->context; + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->read_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int dio_state; + uint32_t val; + int ret; + int i; + + /* first we test if something unusual has just happened */ + switch (urb->status) { + case 0: + /* copy the result in the transfer buffer */ + memcpy(devpriv->in_buf, urb->transfer_buffer, SIZEINBUF); + break; + case -EILSEQ: + /* + * error in the ISOchronous data + * we don't copy the data into the transfer buffer + * and recycle the last data byte + */ + dev_dbg(dev->class_dev, "CRC error in ISO IN stream\n"); + + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -ECONNABORTED: + /* happens after an unlink command */ + if (devpriv->ai_cmd_running) { + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + /* we are still running a command, tell comedi */ + s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); + comedi_event(dev, s); + } + return; + + default: + /* + * a real error on the bus + * pass error to comedi if we are really running a command + */ + if (devpriv->ai_cmd_running) { + dev_err(dev->class_dev, + "%s: non-zero urb status (%d)\n", + __func__, urb->status); + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); + comedi_event(dev, s); + } + return; + } + + if (unlikely(!devpriv->ai_cmd_running)) + return; + + urb->dev = comedi_to_usb_dev(dev); + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(ret < 0)) { + dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", + __func__, ret); + if (ret == -EL2NSYNC) + dev_err(dev->class_dev, + "buggy USB host controller or bug in IRQ handler\n"); + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); + comedi_event(dev, s); + return; + } + + /* get the state of the dio pins to allow external trigger */ + dio_state = be32_to_cpu(devpriv->in_buf[0]); + + devpriv->ai_counter--; + if (likely(devpriv->ai_counter > 0)) + return; + + /* timer zero, transfer measurements to comedi */ + devpriv->ai_counter = devpriv->ai_timer; + + if (cmd->stop_src == TRIG_COUNT) { + /* not continuous, fixed number of samples */ + devpriv->ai_sample_count--; + if (devpriv->ai_sample_count < 0) { + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + /* acquistion is over, tell comedi */ + s->async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); + return; + } + } + + /* get the data from the USB bus and hand it over to comedi */ + for (i = 0; i < cmd->chanlist_len; i++) { + /* transfer data, note first byte is the DIO state */ + val = be32_to_cpu(devpriv->in_buf[i+1]); + val &= 0x00ffffff; /* strip status byte */ + val ^= 0x00800000; /* convert to unsigned */ + + ret = cfc_write_array_to_buffer(s, &val, sizeof(uint32_t)); + if (unlikely(ret == 0)) { + /* buffer overflow */ + usbduxsigma_ai_stop(dev, 0); /* w/o unlink */ + return; + } + } + /* tell comedi that data is there */ + s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS); + comedi_event(dev, s); +} + +static void usbduxsigma_ao_stop(struct comedi_device *dev, int do_unlink) +{ + struct usbduxsigma_private *devpriv = dev->private; + + if (do_unlink && devpriv->ao_urbs) + usbduxsigma_unlink_urbs(devpriv->ao_urbs, devpriv->n_ao_urbs); + + devpriv->ao_cmd_running = 0; +} + +static int usbduxsigma_ao_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct usbduxsigma_private *devpriv = dev->private; + + down(&devpriv->sem); + /* unlink only if it is really running */ + usbduxsigma_ao_stop(dev, devpriv->ao_cmd_running); + up(&devpriv->sem); + + return 0; +} + +static void usbduxsigma_ao_urb_complete(struct urb *urb) +{ + struct comedi_device *dev = urb->context; + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_subdevice *s = dev->write_subdev; + struct comedi_cmd *cmd = &s->async->cmd; + uint8_t *datap; + int ret; + int i; + + switch (urb->status) { + case 0: + /* success */ + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -ECONNABORTED: + /* happens after an unlink command */ + if (devpriv->ao_cmd_running) { + usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ + s->async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); + } + return; + + default: + /* a real error */ + if (devpriv->ao_cmd_running) { + dev_err(dev->class_dev, + "%s: non-zero urb status (%d)\n", + __func__, urb->status); + usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ + s->async->events |= (COMEDI_CB_ERROR | COMEDI_CB_EOA); + comedi_event(dev, s); + } + return; + } + + if (!devpriv->ao_cmd_running) + return; + + devpriv->ao_counter--; + if ((int)devpriv->ao_counter <= 0) { + /* timer zero, transfer from comedi */ + devpriv->ao_counter = devpriv->ao_timer; + + if (cmd->stop_src == TRIG_COUNT) { + /* not continuous, fixed number of samples */ + devpriv->ao_sample_count--; + if (devpriv->ao_sample_count < 0) { + usbduxsigma_ao_stop(dev, 0); /* w/o unlink */ + /* acquistion is over, tell comedi */ + s->async->events |= COMEDI_CB_EOA; + comedi_event(dev, s); + return; + } + } + + /* transmit data to the USB bus */ + datap = urb->transfer_buffer; + *datap++ = cmd->chanlist_len; + for (i = 0; i < cmd->chanlist_len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + unsigned short val; + + ret = comedi_buf_get(s, &val); + if (ret < 0) { + dev_err(dev->class_dev, "buffer underflow\n"); + s->async->events |= (COMEDI_CB_EOA | + COMEDI_CB_OVERFLOW); + } + *datap++ = val; + *datap++ = chan; + devpriv->ao_readback[chan] = val; + + s->async->events |= COMEDI_CB_BLOCK; + comedi_event(dev, s); + } + } + + urb->transfer_buffer_length = SIZEOUTBUF; + urb->dev = comedi_to_usb_dev(dev); + urb->status = 0; + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ + urb->number_of_packets = 1; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEOUTBUF; + urb->iso_frame_desc[0].status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(dev->class_dev, + "%s: urb resubmit failed (%d)\n", + __func__, ret); + 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 */ + s->async->events |= (COMEDI_CB_EOA | COMEDI_CB_ERROR); + comedi_event(dev, s); + } +} + +static int usbduxsigma_submit_urbs(struct comedi_device *dev, + struct urb **urbs, int num_urbs, + int input_urb) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + struct urb *urb; + int ret; + int i; + + /* Submit all URBs and start the transfer on the bus */ + for (i = 0; i < num_urbs; i++) { + urb = urbs[i]; + + /* in case of a resubmission after an unlink... */ + if (input_urb) + urb->interval = devpriv->ai_interval; + urb->context = dev; + urb->dev = usb; + urb->status = 0; + urb->transfer_flags = URB_ISO_ASAP; + + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + return ret; + } + return 0; +} + +static int usbduxsigma_chans_to_interval(int num_chan) +{ + if (num_chan <= 2) + return 2; /* 4kHz */ + if (num_chan <= 8) + return 4; /* 2kHz */ + return 8; /* 1kHz */ +} + +static int usbduxsigma_ai_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + struct usbduxsigma_private *devpriv = dev->private; + int high_speed = devpriv->high_speed; + int interval = usbduxsigma_chans_to_interval(cmd->chanlist_len); + int err = 0; + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, 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_NONE); + + 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->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + + if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */ + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + + if (cmd->scan_begin_src == TRIG_TIMER) { + unsigned int tmp; + + if (high_speed) { + /* + * In high speed mode microframes are possible. + * However, during one microframe we can roughly + * sample two channels. Thus, the more channels + * are in the channel list the more time we need. + */ + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + (1000000 / 8 * interval)); + + tmp = (cmd->scan_begin_arg / 125000) * 125000; + } else { + /* full speed */ + /* 1kHz scans every USB frame */ + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + 1000000); + + tmp = (cmd->scan_begin_arg / 1000000) * 1000000; + } + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, tmp); + } + + 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 */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + } + + if (err) + return 3; + + /* Step 4: fix up any arguments */ + + if (high_speed) { + /* + * every 2 channels get a time window of 125us. Thus, if we + * sample all 16 channels we need 1ms. If we sample only one + * channel we need only 125us + */ + devpriv->ai_interval = interval; + devpriv->ai_timer = cmd->scan_begin_arg / (125000 * interval); + } else { + /* interval always 1ms */ + devpriv->ai_interval = 1; + devpriv->ai_timer = cmd->scan_begin_arg / 1000000; + } + if (devpriv->ai_timer < 1) + err |= -EINVAL; + + if (cmd->stop_src == TRIG_COUNT) { + /* data arrives as one packet */ + devpriv->ai_sample_count = cmd->stop_arg; + } else { + /* continuous acquisition */ + devpriv->ai_sample_count = 0; + } + + if (err) + return 4; + + return 0; +} + +/* + * creates the ADC command for the MAX1271 + * range is the range value from comedi + */ +static void create_adc_command(unsigned int chan, + uint8_t *muxsg0, + uint8_t *muxsg1) +{ + if (chan < 8) + (*muxsg0) = (*muxsg0) | (1 << chan); + else if (chan < 16) + (*muxsg1) = (*muxsg1) | (1 << (chan-8)); +} + +static int usbbuxsigma_send_cmd(struct comedi_device *dev, int cmd_type) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + int nsent; + + devpriv->dux_commands[0] = cmd_type; + + return usb_bulk_msg(usb, usb_sndbulkpipe(usb, 1), + devpriv->dux_commands, SIZEOFDUXBUFFER, + &nsent, BULK_TIMEOUT); +} + +static int usbduxsigma_receive_cmd(struct comedi_device *dev, int command) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + int nrec; + int ret; + int i; + + for (i = 0; i < RETRIES; i++) { + ret = usb_bulk_msg(usb, usb_rcvbulkpipe(usb, 8), + devpriv->insn_buf, SIZEINSNBUF, + &nrec, BULK_TIMEOUT); + if (ret < 0) + return ret; + + if (devpriv->insn_buf[0] == command) + return 0; + } + /* + * This is only reached if the data has been requested a + * couple of times and the command was not received. + */ + return -EFAULT; +} + +static int usbduxsigma_ai_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) +{ + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; + + if (trig_num != cmd->start_arg) + return -EINVAL; + + down(&devpriv->sem); + if (!devpriv->ai_cmd_running) { + devpriv->ai_cmd_running = 1; + ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs, + devpriv->n_ai_urbs, 1); + if (ret < 0) { + devpriv->ai_cmd_running = 0; + up(&devpriv->sem); + return ret; + } + s->async->inttrig = NULL; + } + up(&devpriv->sem); + + return 1; +} + +static int usbduxsigma_ai_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + unsigned int len = cmd->chanlist_len; + uint8_t muxsg0 = 0; + uint8_t muxsg1 = 0; + uint8_t sysred = 0; + int ret; + int i; + + down(&devpriv->sem); + + /* set current channel of the running acquisition to zero */ + s->async->cur_chan = 0; + for (i = 0; i < len; i++) { + unsigned int chan = CR_CHAN(cmd->chanlist[i]); + + create_adc_command(chan, &muxsg0, &muxsg1); + } + + devpriv->dux_commands[1] = len; /* num channels per time step */ + devpriv->dux_commands[2] = 0x12; /* CONFIG0 */ + devpriv->dux_commands[3] = 0x03; /* CONFIG1: 23kHz sample, delay 0us */ + devpriv->dux_commands[4] = 0x00; /* CONFIG3: diff. channels off */ + devpriv->dux_commands[5] = muxsg0; + devpriv->dux_commands[6] = muxsg1; + devpriv->dux_commands[7] = sysred; + + ret = usbbuxsigma_send_cmd(dev, USBBUXSIGMA_AD_CMD); + if (ret < 0) { + up(&devpriv->sem); + return ret; + } + + devpriv->ai_counter = devpriv->ai_timer; + + if (cmd->start_src == TRIG_NOW) { + /* enable this acquisition operation */ + devpriv->ai_cmd_running = 1; + ret = usbduxsigma_submit_urbs(dev, devpriv->ai_urbs, + devpriv->n_ai_urbs, 1); + if (ret < 0) { + devpriv->ai_cmd_running = 0; + up(&devpriv->sem); + return ret; + } + s->async->inttrig = NULL; + } else { /* TRIG_INT */ + s->async->inttrig = usbduxsigma_ai_inttrig; + } + + up(&devpriv->sem); + + return 0; +} + +static int usbduxsigma_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct usbduxsigma_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + uint8_t muxsg0 = 0; + uint8_t muxsg1 = 0; + uint8_t sysred = 0; + int ret; + int i; + + down(&devpriv->sem); + if (devpriv->ai_cmd_running) { + up(&devpriv->sem); + return -EBUSY; + } + + create_adc_command(chan, &muxsg0, &muxsg1); + + /* Mode 0 is used to get a single conversion on demand */ + devpriv->dux_commands[1] = 0x16; /* CONFIG0: chopper on */ + devpriv->dux_commands[2] = 0x80; /* CONFIG1: 2kHz sampling rate */ + devpriv->dux_commands[3] = 0x00; /* CONFIG3: diff. channels off */ + devpriv->dux_commands[4] = muxsg0; + devpriv->dux_commands[5] = muxsg1; + devpriv->dux_commands[6] = sysred; + + /* adc commands */ + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); + if (ret < 0) { + up(&devpriv->sem); + return ret; + } + + for (i = 0; i < insn->n; i++) { + uint32_t val; + + ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); + if (ret < 0) { + up(&devpriv->sem); + return ret; + } + + /* 32 bits big endian from the A/D converter */ + val = be32_to_cpu(get_unaligned((uint32_t + *)(devpriv->insn_buf + 1))); + val &= 0x00ffffff; /* strip status byte */ + val ^= 0x00800000; /* convert to unsigned */ + + data[i] = val; + } + up(&devpriv->sem); + + return insn->n; +} + +static int usbduxsigma_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct usbduxsigma_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int i; + + down(&devpriv->sem); + for (i = 0; i < insn->n; i++) + data[i] = devpriv->ao_readback[chan]; + up(&devpriv->sem); + + return insn->n; +} + +static int usbduxsigma_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct usbduxsigma_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int ret; + int i; + + down(&devpriv->sem); + if (devpriv->ao_cmd_running) { + up(&devpriv->sem); + return -EBUSY; + } + + for (i = 0; i < insn->n; i++) { + devpriv->dux_commands[1] = 1; /* num channels */ + devpriv->dux_commands[2] = data[i]; /* value */ + devpriv->dux_commands[3] = chan; /* channel number */ + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_DA_CMD); + if (ret < 0) { + up(&devpriv->sem); + return ret; + } + devpriv->ao_readback[chan] = data[i]; + } + up(&devpriv->sem); + + return insn->n; +} + +static int usbduxsigma_ao_inttrig(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int trig_num) +{ + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; + + if (trig_num != cmd->start_arg) + return -EINVAL; + + down(&devpriv->sem); + if (!devpriv->ao_cmd_running) { + devpriv->ao_cmd_running = 1; + ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs, + devpriv->n_ao_urbs, 0); + if (ret < 0) { + devpriv->ao_cmd_running = 0; + up(&devpriv->sem); + return ret; + } + s->async->inttrig = NULL; + } + up(&devpriv->sem); + + return 1; +} + +static int usbduxsigma_ao_cmdtest(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) +{ + struct usbduxsigma_private *devpriv = dev->private; + int err = 0; + int high_speed; + unsigned int flags; + + /* high speed conversions are not used yet */ + high_speed = 0; /* (devpriv->high_speed) */ + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + + if (high_speed) { + /* + * start immediately a new scan + * the sampling rate is set by the coversion rate + */ + flags = TRIG_FOLLOW; + } else { + /* start a new scan (output at once) with a timer */ + flags = TRIG_TIMER; + } + err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags); + + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (err) { + up(&devpriv->sem); + 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->stop_src); + + /* Step 2b : and mutually compatible */ + + if (err) + return 2; + + /* Step 3: check if arguments are trivially valid */ + + err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); + + if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */ + err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); + + if (cmd->scan_begin_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, + 1000000); + + /* not used now, is for later use */ + if (cmd->convert_src == TRIG_TIMER) + err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 125000); + + 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 */ + err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); + } + + if (err) + return 3; + + /* Step 4: fix up any arguments */ + + /* we count in timer steps */ + if (high_speed) { + /* timing of the conversion itself: every 125 us */ + devpriv->ao_timer = cmd->convert_arg / 125000; + } else { + /* + * timing of the scan: every 1ms + * we get all channels at once + */ + devpriv->ao_timer = cmd->scan_begin_arg / 1000000; + } + if (devpriv->ao_timer < 1) + err |= -EINVAL; + + if (cmd->stop_src == TRIG_COUNT) { + /* not continuous, use counter */ + if (high_speed) { + /* high speed also scans everything at once */ + devpriv->ao_sample_count = cmd->stop_arg * + cmd->scan_end_arg; + } else { + /* + * There's no scan as the scan has been + * handled inside the FX2. Data arrives as + * one packet. + */ + devpriv->ao_sample_count = cmd->stop_arg; + } + } else { + /* continuous acquisition */ + devpriv->ao_sample_count = 0; + } + + if (err) + return 4; + + return 0; +} + +static int usbduxsigma_ao_cmd(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct usbduxsigma_private *devpriv = dev->private; + struct comedi_cmd *cmd = &s->async->cmd; + int ret; + + down(&devpriv->sem); + + /* set current channel of the running acquisition to zero */ + s->async->cur_chan = 0; + + devpriv->ao_counter = devpriv->ao_timer; + + if (cmd->start_src == TRIG_NOW) { + /* enable this acquisition operation */ + devpriv->ao_cmd_running = 1; + ret = usbduxsigma_submit_urbs(dev, devpriv->ao_urbs, + devpriv->n_ao_urbs, 0); + if (ret < 0) { + devpriv->ao_cmd_running = 0; + up(&devpriv->sem); + return ret; + } + s->async->inttrig = NULL; + } else { /* TRIG_INT */ + s->async->inttrig = usbduxsigma_ao_inttrig; + } + + up(&devpriv->sem); + + return 0; +} + +static int usbduxsigma_dio_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + int ret; + + ret = comedi_dio_insn_config(dev, s, insn, data, 0); + if (ret) + return ret; + + /* + * We don't tell the firmware here as it would take 8 frames + * to submit the information. We do it in the (*insn_bits). + */ + return insn->n; +} + +static int usbduxsigma_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct usbduxsigma_private *devpriv = dev->private; + int ret; + + down(&devpriv->sem); + + comedi_dio_update_state(s, data); + + /* Always update the hardware. See the (*insn_config). */ + devpriv->dux_commands[1] = s->io_bits & 0xff; + devpriv->dux_commands[4] = s->state & 0xff; + devpriv->dux_commands[2] = (s->io_bits >> 8) & 0xff; + devpriv->dux_commands[5] = (s->state >> 8) & 0xff; + devpriv->dux_commands[3] = (s->io_bits >> 16) & 0xff; + devpriv->dux_commands[6] = (s->state >> 16) & 0xff; + + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_DIO_BITS_CMD); + if (ret < 0) + goto done; + ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_DIO_BITS_CMD); + if (ret < 0) + goto done; + + s->state = devpriv->insn_buf[1] | + (devpriv->insn_buf[2] << 8) | + (devpriv->insn_buf[3] << 16); + + data[1] = s->state; + ret = insn->n; + +done: + up(&devpriv->sem); + + return ret; +} + +static void usbduxsigma_pwm_stop(struct comedi_device *dev, int do_unlink) +{ + struct usbduxsigma_private *devpriv = dev->private; + + if (do_unlink) { + if (devpriv->pwm_urb) + usb_kill_urb(devpriv->pwm_urb); + } + + devpriv->pwm_cmd_running = 0; +} + +static int usbduxsigma_pwm_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct usbduxsigma_private *devpriv = dev->private; + + /* unlink only if it is really running */ + usbduxsigma_pwm_stop(dev, devpriv->pwm_cmd_running); + + return usbbuxsigma_send_cmd(dev, USBDUXSIGMA_PWM_OFF_CMD); +} + +static void usbduxsigma_pwm_urb_complete(struct urb *urb) +{ + struct comedi_device *dev = urb->context; + struct usbduxsigma_private *devpriv = dev->private; + int ret; + + switch (urb->status) { + case 0: + /* success */ + break; + + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + case -ECONNABORTED: + /* happens after an unlink command */ + if (devpriv->pwm_cmd_running) + usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */ + return; + + default: + /* a real error */ + if (devpriv->pwm_cmd_running) { + dev_err(dev->class_dev, + "%s: non-zero urb status (%d)\n", + __func__, urb->status); + usbduxsigma_pwm_stop(dev, 0); /* w/o unlink */ + } + return; + } + + if (!devpriv->pwm_cmd_running) + return; + + urb->transfer_buffer_length = devpriv->pwm_buf_sz; + urb->dev = comedi_to_usb_dev(dev); + urb->status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + dev_err(dev->class_dev, "%s: urb resubmit failed (%d)\n", + __func__, ret); + 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 */ + } +} + +static int usbduxsigma_submit_pwm_urb(struct comedi_device *dev) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + struct urb *urb = devpriv->pwm_urb; + + /* in case of a resubmission after an unlink... */ + usb_fill_bulk_urb(urb, usb, usb_sndbulkpipe(usb, 4), + urb->transfer_buffer, devpriv->pwm_buf_sz, + usbduxsigma_pwm_urb_complete, dev); + + return usb_submit_urb(urb, GFP_ATOMIC); +} + +static int usbduxsigma_pwm_period(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int period) +{ + struct usbduxsigma_private *devpriv = dev->private; + int fx2delay = 255; + + if (period < MIN_PWM_PERIOD) { + return -EAGAIN; + } else { + fx2delay = (period / (6 * 512 * 1000 / 33)) - 6; + if (fx2delay > 255) + return -EAGAIN; + } + devpriv->pwm_delay = fx2delay; + devpriv->pwm_period = period; + return 0; +} + +static int usbduxsigma_pwm_start(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct usbduxsigma_private *devpriv = dev->private; + int ret; + + if (devpriv->pwm_cmd_running) + return 0; + + devpriv->dux_commands[1] = devpriv->pwm_delay; + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_PWM_ON_CMD); + if (ret < 0) + return ret; + + memset(devpriv->pwm_urb->transfer_buffer, 0, devpriv->pwm_buf_sz); + + devpriv->pwm_cmd_running = 1; + ret = usbduxsigma_submit_pwm_urb(dev); + if (ret < 0) { + devpriv->pwm_cmd_running = 0; + return ret; + } + + return 0; +} + +static void usbduxsigma_pwm_pattern(struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int chan, + unsigned int value, + unsigned int sign) +{ + struct usbduxsigma_private *devpriv = dev->private; + char pwm_mask = (1 << chan); /* DIO bit for the PWM data */ + char sgn_mask = (16 << chan); /* DIO bit for the sign */ + char *buf = (char *)(devpriv->pwm_urb->transfer_buffer); + int szbuf = devpriv->pwm_buf_sz; + int i; + + for (i = 0; i < szbuf; i++) { + char c = *buf; + + c &= ~pwm_mask; + if (i < value) + c |= pwm_mask; + if (!sign) + c &= ~sgn_mask; + else + c |= sgn_mask; + *buf++ = c; + } +} + +static int usbduxsigma_pwm_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int chan = CR_CHAN(insn->chanspec); + + /* + * It doesn't make sense to support more than one value here + * because it would just overwrite the PWM buffer. + */ + if (insn->n != 1) + return -EINVAL; + + /* + * The sign is set via a special INSN only, this gives us 8 bits + * for normal operation, sign is 0 by default. + */ + usbduxsigma_pwm_pattern(dev, s, chan, data[0], 0); + + return insn->n; +} + +static int usbduxsigma_pwm_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct usbduxsigma_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + + switch (data[0]) { + case INSN_CONFIG_ARM: + /* + * if not zero the PWM is limited to a certain time which is + * not supported here + */ + if (data[1] != 0) + return -EINVAL; + return usbduxsigma_pwm_start(dev, s); + case INSN_CONFIG_DISARM: + return usbduxsigma_pwm_cancel(dev, s); + case INSN_CONFIG_GET_PWM_STATUS: + data[1] = devpriv->pwm_cmd_running; + return 0; + case INSN_CONFIG_PWM_SET_PERIOD: + return usbduxsigma_pwm_period(dev, s, data[1]); + case INSN_CONFIG_PWM_GET_PERIOD: + data[1] = devpriv->pwm_period; + return 0; + case INSN_CONFIG_PWM_SET_H_BRIDGE: + /* + * data[1] = value + * data[2] = sign (for a relay) + */ + usbduxsigma_pwm_pattern(dev, s, chan, data[1], (data[2] != 0)); + return 0; + case INSN_CONFIG_PWM_GET_H_BRIDGE: + /* values are not kept in this driver, nothing to return */ + return -EINVAL; + } + return -EINVAL; +} + +static int usbduxsigma_getstatusinfo(struct comedi_device *dev, int chan) +{ + struct usbduxsigma_private *devpriv = dev->private; + uint8_t sysred; + uint32_t val; + int ret; + + switch (chan) { + default: + case 0: + sysred = 0; /* ADC zero */ + break; + case 1: + sysred = 1; /* ADC offset */ + break; + case 2: + sysred = 4; /* VCC */ + break; + case 3: + sysred = 8; /* temperature */ + break; + case 4: + sysred = 16; /* gain */ + break; + case 5: + sysred = 32; /* ref */ + break; + } + + devpriv->dux_commands[1] = 0x12; /* CONFIG0 */ + devpriv->dux_commands[2] = 0x80; /* CONFIG1: 2kHz sampling rate */ + devpriv->dux_commands[3] = 0x00; /* CONFIG3: diff. channels off */ + devpriv->dux_commands[4] = 0; + devpriv->dux_commands[5] = 0; + devpriv->dux_commands[6] = sysred; + ret = usbbuxsigma_send_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); + if (ret < 0) + return ret; + + ret = usbduxsigma_receive_cmd(dev, USBDUXSIGMA_SINGLE_AD_CMD); + if (ret < 0) + return ret; + + /* 32 bits big endian from the A/D converter */ + val = be32_to_cpu(get_unaligned((uint32_t *)(devpriv->insn_buf + 1))); + val &= 0x00ffffff; /* strip status byte */ + val ^= 0x00800000; /* convert to unsigned */ + + return (int)val; +} + +static int usbduxsigma_firmware_upload(struct comedi_device *dev, + const u8 *data, size_t size, + unsigned long context) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + uint8_t *buf; + uint8_t *tmp; + int ret; + + if (!data) + return 0; + + if (size > FIRMWARE_MAX_LEN) { + dev_err(dev->class_dev, "firmware binary too large for FX2\n"); + return -ENOMEM; + } + + /* we generate a local buffer for the firmware */ + buf = kmemdup(data, size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + /* we need a malloc'ed buffer for usb_control_msg() */ + tmp = kmalloc(1, GFP_KERNEL); + if (!tmp) { + kfree(buf); + return -ENOMEM; + } + + /* stop the current firmware on the device */ + *tmp = 1; /* 7f92 to one */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXSUB_CPUCS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "can not stop firmware\n"); + goto done; + } + + /* upload the new firmware to the device */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + 0, 0x0000, + buf, size, + BULK_TIMEOUT); + if (ret < 0) { + dev_err(dev->class_dev, "firmware upload failed\n"); + goto done; + } + + /* start the new firmware on the device */ + *tmp = 0; /* 7f92 to zero */ + ret = usb_control_msg(usb, usb_sndctrlpipe(usb, 0), + USBDUXSUB_FIRMWARE, + VENDOR_DIR_OUT, + USBDUXSUB_CPUCS, 0x0000, + tmp, 1, + BULK_TIMEOUT); + if (ret < 0) + dev_err(dev->class_dev, "can not start firmware\n"); + +done: + kfree(tmp); + kfree(buf); + return ret; +} + +static int usbduxsigma_alloc_usb_buffers(struct comedi_device *dev) +{ + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv = dev->private; + struct urb *urb; + int i; + + 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); + if (!devpriv->dux_commands || !devpriv->in_buf || !devpriv->insn_buf || + !devpriv->ai_urbs || !devpriv->ao_urbs) + return -ENOMEM; + + for (i = 0; i < devpriv->n_ai_urbs; i++) { + /* one frame: 1ms */ + urb = usb_alloc_urb(1, GFP_KERNEL); + if (!urb) + return -ENOMEM; + devpriv->ai_urbs[i] = urb; + urb->dev = usb; + /* will be filled later with a pointer to the comedi-device */ + /* and ONLY then the urb should be submitted */ + urb->context = NULL; + urb->pipe = usb_rcvisocpipe(usb, 6); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = kzalloc(SIZEINBUF, GFP_KERNEL); + if (!urb->transfer_buffer) + return -ENOMEM; + urb->complete = usbduxsigma_ai_urb_complete; + urb->number_of_packets = 1; + urb->transfer_buffer_length = SIZEINBUF; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEINBUF; + } + + for (i = 0; i < devpriv->n_ao_urbs; i++) { + /* one frame: 1ms */ + urb = usb_alloc_urb(1, GFP_KERNEL); + if (!urb) + return -ENOMEM; + devpriv->ao_urbs[i] = urb; + urb->dev = usb; + /* will be filled later with a pointer to the comedi-device */ + /* and ONLY then the urb should be submitted */ + urb->context = NULL; + urb->pipe = usb_sndisocpipe(usb, 2); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = kzalloc(SIZEOUTBUF, GFP_KERNEL); + if (!urb->transfer_buffer) + return -ENOMEM; + urb->complete = usbduxsigma_ao_urb_complete; + urb->number_of_packets = 1; + urb->transfer_buffer_length = SIZEOUTBUF; + urb->iso_frame_desc[0].offset = 0; + urb->iso_frame_desc[0].length = SIZEOUTBUF; + if (devpriv->high_speed) + urb->interval = 8; /* uframes */ + else + urb->interval = 1; /* frames */ + } + + if (devpriv->pwm_buf_sz) { + urb = usb_alloc_urb(0, GFP_KERNEL); + if (!urb) + return -ENOMEM; + devpriv->pwm_urb = urb; + + urb->transfer_buffer = kzalloc(devpriv->pwm_buf_sz, + GFP_KERNEL); + if (!urb->transfer_buffer) + return -ENOMEM; + } + + return 0; +} + +static void usbduxsigma_free_usb_buffers(struct comedi_device *dev) +{ + struct usbduxsigma_private *devpriv = dev->private; + struct urb *urb; + int i; + + urb = devpriv->pwm_urb; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + if (devpriv->ao_urbs) { + for (i = 0; i < devpriv->n_ao_urbs; i++) { + urb = devpriv->ao_urbs[i]; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } + kfree(devpriv->ao_urbs); + } + if (devpriv->ai_urbs) { + for (i = 0; i < devpriv->n_ai_urbs; i++) { + urb = devpriv->ai_urbs[i]; + if (urb) { + kfree(urb->transfer_buffer); + usb_free_urb(urb); + } + } + kfree(devpriv->ai_urbs); + } + kfree(devpriv->insn_buf); + kfree(devpriv->in_buf); + kfree(devpriv->dux_commands); +} + +static int usbduxsigma_auto_attach(struct comedi_device *dev, + unsigned long context_unused) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usbduxsigma_private *devpriv; + struct comedi_subdevice *s; + int offset; + int ret; + + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; + + sema_init(&devpriv->sem, 1); + + usb_set_intfdata(intf, devpriv); + + devpriv->high_speed = (usb->speed == USB_SPEED_HIGH); + if (devpriv->high_speed) { + devpriv->n_ai_urbs = NUMOFINBUFFERSHIGH; + devpriv->n_ao_urbs = NUMOFOUTBUFFERSHIGH; + devpriv->pwm_buf_sz = 512; + } else { + devpriv->n_ai_urbs = NUMOFINBUFFERSFULL; + devpriv->n_ao_urbs = NUMOFOUTBUFFERSFULL; + } + + ret = usbduxsigma_alloc_usb_buffers(dev); + if (ret) + return ret; + + /* setting to alternate setting 3: enabling iso ep and bulk ep. */ + ret = usb_set_interface(usb, intf->altsetting->desc.bInterfaceNumber, + 3); + if (ret < 0) { + dev_err(dev->class_dev, + "could not set alternate setting 3 in high speed\n"); + return ret; + } + + ret = comedi_load_firmware(dev, &usb->dev, FIRMWARE, + usbduxsigma_firmware_upload, 0); + if (ret) + return ret; + + ret = comedi_alloc_subdevices(dev, (devpriv->high_speed) ? 4 : 3); + if (ret) + return ret; + + /* Analog Input subdevice */ + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ | SDF_LSAMPL; + s->n_chan = NUMCHANNELS; + s->len_chanlist = NUMCHANNELS; + s->maxdata = 0x00ffffff; + s->range_table = &usbduxsigma_ai_range; + s->insn_read = usbduxsigma_ai_insn_read; + s->do_cmdtest = usbduxsigma_ai_cmdtest; + s->do_cmd = usbduxsigma_ai_cmd; + s->cancel = usbduxsigma_ai_cancel; + + /* Analog Output subdevice */ + s = &dev->subdevices[1]; + 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->len_chanlist = s->n_chan; + s->maxdata = 0x00ff; + s->range_table = &range_unipolar2_5; + s->insn_write = usbduxsigma_ao_insn_write; + s->insn_read = usbduxsigma_ao_insn_read; + s->do_cmdtest = usbduxsigma_ao_cmdtest; + s->do_cmd = usbduxsigma_ao_cmd; + s->cancel = usbduxsigma_ao_cancel; + + /* Digital I/O subdevice */ + s = &dev->subdevices[2]; + 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 = usbduxsigma_dio_insn_bits; + s->insn_config = usbduxsigma_dio_insn_config; + + if (devpriv->high_speed) { + /* Timer / pwm subdevice */ + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; + s->n_chan = 8; + s->maxdata = devpriv->pwm_buf_sz; + s->insn_write = usbduxsigma_pwm_write; + s->insn_config = usbduxsigma_pwm_config; + + usbduxsigma_pwm_period(dev, s, PWM_DEFAULT_PERIOD); + } + + offset = usbduxsigma_getstatusinfo(dev, 0); + if (offset < 0) { + dev_err(dev->class_dev, + "Communication to USBDUXSIGMA failed! Check firmware and cabling.\n"); + return offset; + } + + dev_info(dev->class_dev, "ADC_zero = %x\n", offset); + + return 0; +} + +static void usbduxsigma_detach(struct comedi_device *dev) +{ + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usbduxsigma_private *devpriv = dev->private; + + usb_set_intfdata(intf, NULL); + + if (!devpriv) + return; + + down(&devpriv->sem); + + /* force unlink all urbs */ + usbduxsigma_ai_stop(dev, 1); + usbduxsigma_ao_stop(dev, 1); + usbduxsigma_pwm_stop(dev, 1); + + usbduxsigma_free_usb_buffers(dev); + + up(&devpriv->sem); +} + +static struct comedi_driver usbduxsigma_driver = { + .driver_name = "usbduxsigma", + .module = THIS_MODULE, + .auto_attach = usbduxsigma_auto_attach, + .detach = usbduxsigma_detach, +}; + +static int usbduxsigma_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return comedi_usb_auto_config(intf, &usbduxsigma_driver, 0); +} + +static const struct usb_device_id usbduxsigma_usb_table[] = { + { USB_DEVICE(0x13d8, 0x0020) }, + { USB_DEVICE(0x13d8, 0x0021) }, + { USB_DEVICE(0x13d8, 0x0022) }, + { } +}; +MODULE_DEVICE_TABLE(usb, usbduxsigma_usb_table); + +static struct usb_driver usbduxsigma_usb_driver = { + .name = "usbduxsigma", + .probe = usbduxsigma_usb_probe, + .disconnect = comedi_usb_auto_unconfig, + .id_table = usbduxsigma_usb_table, +}; +module_comedi_usb_driver(usbduxsigma_driver, usbduxsigma_usb_driver); + +MODULE_AUTHOR("Bernd Porr, BerndPorr@f2s.com"); +MODULE_DESCRIPTION("Stirling/ITL USB-DUX SIGMA -- Bernd.Porr@f2s.com"); +MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(FIRMWARE); diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 3d13ca6e167..0adf3cffddb 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -16,11 +16,6 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ /* Driver: vmk80xx @@ -38,19 +33,6 @@ Supports: - counter - pwm */ -/* -Changelog: - -0.8.81 -3- code completely rewritten (adjust driver logic) -0.8.81 -2- full support for K8061 -0.8.81 -1- fix some mistaken among others the number of - supported boards and I/O handling - -0.7.76 -4- renamed to vmk80xx -0.7.76 -3- detect K8061 (only theoretically supported) -0.7.76 -2- code completely rewritten (adjust driver logic) -0.7.76 -1- support for digital and counter subdevice -*/ #include <linux/kernel.h> #include <linux/module.h> @@ -64,37 +46,11 @@ Changelog: #include "../comedidev.h" -#define BOARDNAME "vmk80xx" - -MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>"); -MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver"); -MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140"); -MODULE_VERSION("0.8.01"); -MODULE_LICENSE("GPL"); - enum { DEVICE_VMK8055, DEVICE_VMK8061 }; -static const struct usb_device_id vmk80xx_id_table[] = { - {USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055}, - {USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055}, - {USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055}, - {USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055}, - {USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061}, - {USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061}, - {USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061}, - {USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061}, - {USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061}, - {USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061}, - {USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061}, - {USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061}, - {} /* terminating entry */ -}; - -MODULE_DEVICE_TABLE(usb, vmk80xx_id_table); - #define VMK8055_DI_REG 0x00 #define VMK8055_DO_REG 0x01 #define VMK8055_AO1_REG 0x02 @@ -139,45 +95,9 @@ MODULE_DEVICE_TABLE(usb, vmk80xx_id_table); #define VMK8061_CMD_RD_AO 0x0f #define VMK8061_CMD_RD_PWM 0x10 -#define VMK80XX_MAX_BOARDS COMEDI_NUM_BOARD_MINORS - -#define TRANS_OUT_BUSY 1 -#define TRANS_IN_BUSY 2 -#define TRANS_IN_RUNNING 3 - #define IC3_VERSION (1 << 0) #define IC6_VERSION (1 << 1) -#define URB_RCV_FLAG (1 << 0) -#define URB_SND_FLAG (1 << 1) - -#define CONFIG_VMK80XX_DEBUG -#undef CONFIG_VMK80XX_DEBUG - -#ifdef CONFIG_VMK80XX_DEBUG -static int dbgvm = 1; -#else -static int dbgvm; -#endif - -#ifdef CONFIG_COMEDI_DEBUG -static int dbgcm = 1; -#else -static int dbgcm; -#endif - -#define dbgvm(fmt, arg...) \ -do { \ - if (dbgvm) \ - printk(KERN_DEBUG fmt, ##arg); \ -} while (0) - -#define dbgcm(fmt, arg...) \ -do { \ - if (dbgcm) \ - printk(KERN_DEBUG fmt, ##arg); \ -} while (0) - enum vmk80xx_model { VMK8055_MODEL, VMK8061_MODEL @@ -188,134 +108,72 @@ struct firmware_version { unsigned char ic6_vers[32]; /* CPU */ }; -static const struct comedi_lrange vmk8055_range = { - 1, {UNI_RANGE(5)} -}; - static const struct comedi_lrange vmk8061_range = { - 2, {UNI_RANGE(5), UNI_RANGE(10)} + 2, { + UNI_RANGE(5), + UNI_RANGE(10) + } }; struct vmk80xx_board { const char *name; enum vmk80xx_model model; const struct comedi_lrange *range; - __u8 ai_chans; - __le16 ai_bits; - __u8 ao_chans; - __le16 ao_bits; - __u8 di_chans; - __le16 di_bits; - __u8 do_chans; - __le16 do_bits; - __u8 cnt_chans; - __le16 cnt_bits; - __u8 pwm_chans; - __le16 pwm_bits; + int ai_nchans; + unsigned int ai_maxdata; + int ao_nchans; + int di_nchans; + unsigned int cnt_maxdata; + int pwm_nchans; + unsigned int pwm_maxdata; }; -enum { - VMK80XX_SUBD_AI, - VMK80XX_SUBD_AO, - VMK80XX_SUBD_DI, - VMK80XX_SUBD_DO, - VMK80XX_SUBD_CNT, - VMK80XX_SUBD_PWM, +static const struct vmk80xx_board vmk80xx_boardinfo[] = { + [DEVICE_VMK8055] = { + .name = "K8055 (VM110)", + .model = VMK8055_MODEL, + .range = &range_unipolar5, + .ai_nchans = 2, + .ai_maxdata = 0x00ff, + .ao_nchans = 2, + .di_nchans = 6, + .cnt_maxdata = 0xffff, + }, + [DEVICE_VMK8061] = { + .name = "K8061 (VM140)", + .model = VMK8061_MODEL, + .range = &vmk8061_range, + .ai_nchans = 8, + .ai_maxdata = 0x03ff, + .ao_nchans = 8, + .di_nchans = 8, + .cnt_maxdata = 0, /* unknown, device is not writeable */ + .pwm_nchans = 1, + .pwm_maxdata = 0x03ff, + }, }; -struct vmk80xx_usb { - struct usb_device *udev; - struct usb_interface *intf; +struct vmk80xx_private { struct usb_endpoint_descriptor *ep_rx; struct usb_endpoint_descriptor *ep_tx; - struct usb_anchor rx_anchor; - struct usb_anchor tx_anchor; - struct vmk80xx_board board; struct firmware_version fw; struct semaphore limit_sem; - wait_queue_head_t read_wait; - wait_queue_head_t write_wait; unsigned char *usb_rx_buf; unsigned char *usb_tx_buf; - unsigned long flags; - int probed; - int attached; - int count; + enum vmk80xx_model model; }; -static struct vmk80xx_usb vmb[VMK80XX_MAX_BOARDS]; - -static DEFINE_MUTEX(glb_mutex); - -static void vmk80xx_tx_callback(struct urb *urb) -{ - struct vmk80xx_usb *dev = urb->context; - int stat = urb->status; - - dbgvm("vmk80xx: %s\n", __func__); - - if (stat && !(stat == -ENOENT - || stat == -ECONNRESET || stat == -ESHUTDOWN)) - dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", - __func__, stat); - - if (!test_bit(TRANS_OUT_BUSY, &dev->flags)) - return; - - clear_bit(TRANS_OUT_BUSY, &dev->flags); - - wake_up_interruptible(&dev->write_wait); -} - -static void vmk80xx_rx_callback(struct urb *urb) -{ - struct vmk80xx_usb *dev = urb->context; - int stat = urb->status; - - dbgvm("vmk80xx: %s\n", __func__); - - switch (stat) { - case 0: - break; - case -ENOENT: - case -ECONNRESET: - case -ESHUTDOWN: - break; - default: - dbgcm("comedi#: vmk80xx: %s - nonzero urb status (%d)\n", - __func__, stat); - goto resubmit; - } - - goto exit; -resubmit: - if (test_bit(TRANS_IN_RUNNING, &dev->flags) && dev->intf) { - usb_anchor_urb(urb, &dev->rx_anchor); - - if (!usb_submit_urb(urb, GFP_KERNEL)) - goto exit; - - err("comedi#: vmk80xx: %s - submit urb failed\n", __func__); - - usb_unanchor_urb(urb); - } -exit: - clear_bit(TRANS_IN_BUSY, &dev->flags); - - wake_up_interruptible(&dev->read_wait); -} - -static int vmk80xx_check_data_link(struct vmk80xx_usb *dev) +static int vmk80xx_check_data_link(struct comedi_device *dev) { + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); unsigned int tx_pipe; unsigned int rx_pipe; unsigned char tx[1]; unsigned char rx[2]; - dbgvm("vmk80xx: %s\n", __func__); - - tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); - rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); + tx_pipe = usb_sndbulkpipe(usb, 0x01); + rx_pipe = usb_rcvbulkpipe(usb, 0x81); tx[0] = VMK8061_CMD_RD_PWR_STAT; @@ -324,24 +182,24 @@ static int vmk80xx_check_data_link(struct vmk80xx_usb *dev) * running and the data link between IC3 and * IC6 is working properly */ - usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval); - usb_bulk_msg(dev->udev, rx_pipe, rx, 2, NULL, HZ * 10); + usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval); + usb_bulk_msg(usb, rx_pipe, rx, 2, NULL, HZ * 10); return (int)rx[1]; } -static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag) +static void vmk80xx_read_eeprom(struct comedi_device *dev, int flag) { + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); unsigned int tx_pipe; unsigned int rx_pipe; unsigned char tx[1]; unsigned char rx[64]; int cnt; - dbgvm("vmk80xx: %s\n", __func__); - - tx_pipe = usb_sndbulkpipe(dev->udev, 0x01); - rx_pipe = usb_rcvbulkpipe(dev->udev, 0x81); + tx_pipe = usb_sndbulkpipe(usb, 0x01); + rx_pipe = usb_rcvbulkpipe(usb, 0x81); tx[0] = VMK8061_CMD_RD_VERSION; @@ -349,255 +207,112 @@ static void vmk80xx_read_eeprom(struct vmk80xx_usb *dev, int flag) * Read the firmware version info of IC3 and * IC6 from the internal EEPROM of the IC */ - usb_bulk_msg(dev->udev, tx_pipe, tx, 1, NULL, dev->ep_tx->bInterval); - usb_bulk_msg(dev->udev, rx_pipe, rx, 64, &cnt, HZ * 10); + usb_bulk_msg(usb, tx_pipe, tx, 1, NULL, devpriv->ep_tx->bInterval); + usb_bulk_msg(usb, rx_pipe, rx, 64, &cnt, HZ * 10); rx[cnt] = '\0'; if (flag & IC3_VERSION) - strncpy(dev->fw.ic3_vers, rx + 1, 24); + strncpy(devpriv->fw.ic3_vers, rx + 1, 24); else /* IC6_VERSION */ - strncpy(dev->fw.ic6_vers, rx + 25, 24); -} - -static int vmk80xx_reset_device(struct vmk80xx_usb *dev) -{ - struct urb *urb; - unsigned int tx_pipe; - int ival; - size_t size; - - dbgvm("vmk80xx: %s\n", __func__); - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - tx_pipe = usb_sndintpipe(dev->udev, 0x01); - - ival = dev->ep_tx->bInterval; - size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); - - dev->usb_tx_buf[0] = VMK8055_CMD_RST; - dev->usb_tx_buf[1] = 0x00; - dev->usb_tx_buf[2] = 0x00; - dev->usb_tx_buf[3] = 0x00; - dev->usb_tx_buf[4] = 0x00; - dev->usb_tx_buf[5] = 0x00; - dev->usb_tx_buf[6] = 0x00; - dev->usb_tx_buf[7] = 0x00; - - usb_fill_int_urb(urb, dev->udev, tx_pipe, dev->usb_tx_buf, - size, vmk80xx_tx_callback, dev, ival); - - usb_anchor_urb(urb, &dev->tx_anchor); - - return usb_submit_urb(urb, GFP_KERNEL); -} - -static void vmk80xx_build_int_urb(struct urb *urb, int flag) -{ - struct vmk80xx_usb *dev = urb->context; - __u8 rx_addr; - __u8 tx_addr; - unsigned int pipe; - unsigned char *buf; - size_t size; - void (*callback) (struct urb *); - int ival; - - dbgvm("vmk80xx: %s\n", __func__); - - if (flag & URB_RCV_FLAG) { - rx_addr = dev->ep_rx->bEndpointAddress; - pipe = usb_rcvintpipe(dev->udev, rx_addr); - buf = dev->usb_rx_buf; - size = le16_to_cpu(dev->ep_rx->wMaxPacketSize); - callback = vmk80xx_rx_callback; - ival = dev->ep_rx->bInterval; - } else { /* URB_SND_FLAG */ - tx_addr = dev->ep_tx->bEndpointAddress; - pipe = usb_sndintpipe(dev->udev, tx_addr); - buf = dev->usb_tx_buf; - size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); - callback = vmk80xx_tx_callback; - ival = dev->ep_tx->bInterval; - } - - usb_fill_int_urb(urb, dev->udev, pipe, buf, size, callback, dev, ival); + strncpy(devpriv->fw.ic6_vers, rx + 25, 24); } -static void vmk80xx_do_bulk_msg(struct vmk80xx_usb *dev) +static void vmk80xx_do_bulk_msg(struct comedi_device *dev) { + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); __u8 tx_addr; __u8 rx_addr; unsigned int tx_pipe; unsigned int rx_pipe; size_t size; - dbgvm("vmk80xx: %s\n", __func__); - - set_bit(TRANS_IN_BUSY, &dev->flags); - set_bit(TRANS_OUT_BUSY, &dev->flags); - - tx_addr = dev->ep_tx->bEndpointAddress; - rx_addr = dev->ep_rx->bEndpointAddress; - tx_pipe = usb_sndbulkpipe(dev->udev, tx_addr); - rx_pipe = usb_rcvbulkpipe(dev->udev, rx_addr); + tx_addr = devpriv->ep_tx->bEndpointAddress; + rx_addr = devpriv->ep_rx->bEndpointAddress; + tx_pipe = usb_sndbulkpipe(usb, tx_addr); + rx_pipe = usb_rcvbulkpipe(usb, rx_addr); /* * The max packet size attributes of the K8061 * input/output endpoints are identical */ - size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); - - usb_bulk_msg(dev->udev, tx_pipe, dev->usb_tx_buf, - size, NULL, dev->ep_tx->bInterval); - usb_bulk_msg(dev->udev, rx_pipe, dev->usb_rx_buf, size, NULL, HZ * 10); + size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize); - clear_bit(TRANS_OUT_BUSY, &dev->flags); - clear_bit(TRANS_IN_BUSY, &dev->flags); + usb_bulk_msg(usb, tx_pipe, devpriv->usb_tx_buf, + size, NULL, devpriv->ep_tx->bInterval); + usb_bulk_msg(usb, rx_pipe, devpriv->usb_rx_buf, size, NULL, HZ * 10); } -static int vmk80xx_read_packet(struct vmk80xx_usb *dev) +static int vmk80xx_read_packet(struct comedi_device *dev) { - struct urb *urb; - int retval; - - dbgvm("vmk80xx: %s\n", __func__); - - if (!dev->intf) - return -ENODEV; - - /* Only useful for interrupt transfers */ - if (test_bit(TRANS_IN_BUSY, &dev->flags)) - if (wait_event_interruptible(dev->read_wait, - !test_bit(TRANS_IN_BUSY, - &dev->flags))) - return -ERESTART; + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usb_endpoint_descriptor *ep; + unsigned int pipe; - if (dev->board.model == VMK8061_MODEL) { + if (devpriv->model == VMK8061_MODEL) { vmk80xx_do_bulk_msg(dev); - return 0; } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - urb->context = dev; - vmk80xx_build_int_urb(urb, URB_RCV_FLAG); - - set_bit(TRANS_IN_RUNNING, &dev->flags); - set_bit(TRANS_IN_BUSY, &dev->flags); - - usb_anchor_urb(urb, &dev->rx_anchor); - - retval = usb_submit_urb(urb, GFP_KERNEL); - if (!retval) - goto exit; - - clear_bit(TRANS_IN_RUNNING, &dev->flags); - usb_unanchor_urb(urb); - -exit: - usb_free_urb(urb); - - return retval; + ep = devpriv->ep_rx; + pipe = usb_rcvintpipe(usb, ep->bEndpointAddress); + return usb_interrupt_msg(usb, pipe, devpriv->usb_rx_buf, + le16_to_cpu(ep->wMaxPacketSize), NULL, + HZ * 10); } -static int vmk80xx_write_packet(struct vmk80xx_usb *dev, int cmd) +static int vmk80xx_write_packet(struct comedi_device *dev, int cmd) { - struct urb *urb; - int retval; - - dbgvm("vmk80xx: %s\n", __func__); - - if (!dev->intf) - return -ENODEV; + struct vmk80xx_private *devpriv = dev->private; + struct usb_device *usb = comedi_to_usb_dev(dev); + struct usb_endpoint_descriptor *ep; + unsigned int pipe; - if (test_bit(TRANS_OUT_BUSY, &dev->flags)) - if (wait_event_interruptible(dev->write_wait, - !test_bit(TRANS_OUT_BUSY, - &dev->flags))) - return -ERESTART; + devpriv->usb_tx_buf[0] = cmd; - if (dev->board.model == VMK8061_MODEL) { - dev->usb_tx_buf[0] = cmd; + if (devpriv->model == VMK8061_MODEL) { vmk80xx_do_bulk_msg(dev); - return 0; } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - - urb->context = dev; - vmk80xx_build_int_urb(urb, URB_SND_FLAG); - - set_bit(TRANS_OUT_BUSY, &dev->flags); - - usb_anchor_urb(urb, &dev->tx_anchor); - - dev->usb_tx_buf[0] = cmd; - - retval = usb_submit_urb(urb, GFP_KERNEL); - if (!retval) - goto exit; - - clear_bit(TRANS_OUT_BUSY, &dev->flags); - usb_unanchor_urb(urb); - -exit: - usb_free_urb(urb); - - return retval; + ep = devpriv->ep_tx; + pipe = usb_sndintpipe(usb, ep->bEndpointAddress); + return usb_interrupt_msg(usb, pipe, devpriv->usb_tx_buf, + le16_to_cpu(ep->wMaxPacketSize), NULL, + HZ * 10); } -#define DIR_IN 1 -#define DIR_OUT 2 - -static int rudimentary_check(struct vmk80xx_usb *dev, int dir) +static int vmk80xx_reset_device(struct comedi_device *dev) { - if (!dev) - return -EFAULT; - if (!dev->probed) - return -ENODEV; - if (!dev->attached) - return -ENODEV; - if (dir & DIR_IN) { - if (test_bit(TRANS_IN_BUSY, &dev->flags)) - return -EBUSY; - } - if (dir & DIR_OUT) { - if (test_bit(TRANS_OUT_BUSY, &dev->flags)) - return -EBUSY; - } + struct vmk80xx_private *devpriv = dev->private; + size_t size; + int retval; - return 0; + size = le16_to_cpu(devpriv->ep_tx->wMaxPacketSize); + memset(devpriv->usb_tx_buf, 0, size); + retval = vmk80xx_write_packet(dev, VMK8055_CMD_RST); + if (retval) + return retval; + /* set outputs to known state as we cannot read them */ + return vmk80xx_write_packet(dev, VMK8055_CMD_WRT_AD); } -static int vmk80xx_ai_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_ai_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; int chan; int reg[2]; int n; - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); - switch (dev->board.model) { + switch (devpriv->model) { case VMK8055_MODEL: if (!chan) reg[0] = VMK8055_AI1_REG; @@ -605,10 +320,11 @@ static int vmk80xx_ai_rinsn(struct comedi_device *cdev, reg[0] = VMK8055_AI2_REG; break; case VMK8061_MODEL: + default: reg[0] = VMK8061_AI_REG1; reg[1] = VMK8061_AI_REG2; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI; - dev->usb_tx_buf[VMK8061_CH_REG] = chan; + devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AI; + devpriv->usb_tx_buf[VMK8061_CH_REG] = chan; break; } @@ -616,41 +332,36 @@ static int vmk80xx_ai_rinsn(struct comedi_device *cdev, if (vmk80xx_read_packet(dev)) break; - if (dev->board.model == VMK8055_MODEL) { - data[n] = dev->usb_rx_buf[reg[0]]; + if (devpriv->model == VMK8055_MODEL) { + data[n] = devpriv->usb_rx_buf[reg[0]]; continue; } /* VMK8061_MODEL */ - data[n] = dev->usb_rx_buf[reg[0]] + 256 * - dev->usb_rx_buf[reg[1]]; + data[n] = devpriv->usb_rx_buf[reg[0]] + 256 * + devpriv->usb_rx_buf[reg[1]]; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_ao_winsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; int chan; int cmd; int reg; int n; - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); - switch (dev->board.model) { + switch (devpriv->model) { case VMK8055_MODEL: cmd = VMK8055_CMD_WRT_AD; if (!chan) @@ -661,78 +372,68 @@ static int vmk80xx_ao_winsn(struct comedi_device *cdev, default: /* NOTE: avoid compiler warnings */ cmd = VMK8061_CMD_SET_AO; reg = VMK8061_AO_REG; - dev->usb_tx_buf[VMK8061_CH_REG] = chan; + devpriv->usb_tx_buf[VMK8061_CH_REG] = chan; break; } for (n = 0; n < insn->n; n++) { - dev->usb_tx_buf[reg] = data[n]; + devpriv->usb_tx_buf[reg] = data[n]; if (vmk80xx_write_packet(dev, cmd)) break; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_ao_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_ao_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; int chan; int reg; int n; - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); reg = VMK8061_AO_REG - 1; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_AO; + devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_AO; for (n = 0; n < insn->n; n++) { if (vmk80xx_read_packet(dev)) break; - data[n] = dev->usb_rx_buf[reg + chan]; + data[n] = devpriv->usb_rx_buf[reg + chan]; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_di_bits(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned char *rx_buf; int reg; int retval; - dbgvm("vmk80xx: %s\n", __func__); + down(&devpriv->limit_sem); - retval = rudimentary_check(dev, DIR_IN); - if (retval) - return retval; - - down(&dev->limit_sem); + rx_buf = devpriv->usb_rx_buf; - rx_buf = dev->usb_rx_buf; - - if (dev->board.model == VMK8061_MODEL) { + if (devpriv->model == VMK8061_MODEL) { reg = VMK8061_DI_REG; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI; + devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_DI; } else { reg = VMK8055_DI_REG; } @@ -740,7 +441,7 @@ static int vmk80xx_di_bits(struct comedi_device *cdev, retval = vmk80xx_read_packet(dev); if (!retval) { - if (dev->board.model == VMK8055_MODEL) + if (devpriv->model == VMK8055_MODEL) data[1] = (((rx_buf[reg] >> 4) & 0x03) | ((rx_buf[reg] << 2) & 0x04) | ((rx_buf[reg] >> 3) & 0x18)); @@ -750,228 +451,69 @@ static int vmk80xx_di_bits(struct comedi_device *cdev, retval = 2; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return retval; } -static int vmk80xx_di_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct vmk80xx_usb *dev = cdev->private; - int chan; - unsigned char *rx_buf; - int reg; - int inp; - int n; - - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); - chan = CR_CHAN(insn->chanspec); - - rx_buf = dev->usb_rx_buf; - - if (dev->board.model == VMK8061_MODEL) { - reg = VMK8061_DI_REG; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_DI; - } else { - reg = VMK8055_DI_REG; - } - for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(dev)) - break; - - if (dev->board.model == VMK8055_MODEL) - inp = (((rx_buf[reg] >> 4) & 0x03) | - ((rx_buf[reg] << 2) & 0x04) | - ((rx_buf[reg] >> 3) & 0x18)); - else - inp = rx_buf[reg]; - - data[n] = (inp >> chan) & 1; - } - - up(&dev->limit_sem); - - return n; -} - -static int vmk80xx_do_winsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct vmk80xx_usb *dev = cdev->private; - int chan; - unsigned char *tx_buf; - int reg; - int cmd; - int n; - - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); - chan = CR_CHAN(insn->chanspec); - - tx_buf = dev->usb_tx_buf; - - for (n = 0; n < insn->n; n++) { - if (dev->board.model == VMK8055_MODEL) { - reg = VMK8055_DO_REG; - cmd = VMK8055_CMD_WRT_AD; - if (data[n] == 1) - tx_buf[reg] |= (1 << chan); - else - tx_buf[reg] ^= (1 << chan); - } else { /* VMK8061_MODEL */ - reg = VMK8061_DO_REG; - if (data[n] == 1) { - cmd = VMK8061_CMD_SET_DO; - tx_buf[reg] = 1 << chan; - } else { - cmd = VMK8061_CMD_CLR_DO; - tx_buf[reg] = 0xff - (1 << chan); - } - } - - if (vmk80xx_write_packet(dev, cmd)) - break; - } - - up(&dev->limit_sem); - - return n; -} - -static int vmk80xx_do_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; - int chan; - int reg; - int n; - - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); - chan = CR_CHAN(insn->chanspec); - - reg = VMK8061_DO_REG; - - dev->usb_tx_buf[0] = VMK8061_CMD_RD_DO; - - for (n = 0; n < insn->n; n++) { - if (vmk80xx_read_packet(dev)) - break; + struct vmk80xx_private *devpriv = dev->private; + unsigned char *rx_buf = devpriv->usb_rx_buf; + unsigned char *tx_buf = devpriv->usb_tx_buf; + int reg, cmd; + int ret = 0; - data[n] = (dev->usb_rx_buf[reg] >> chan) & 1; + if (devpriv->model == VMK8061_MODEL) { + reg = VMK8061_DO_REG; + cmd = VMK8061_CMD_DO; + } else { /* VMK8055_MODEL */ + reg = VMK8055_DO_REG; + cmd = VMK8055_CMD_WRT_AD; } - up(&dev->limit_sem); - - return n; -} - -static int vmk80xx_do_bits(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - struct vmk80xx_usb *dev = cdev->private; - unsigned char *rx_buf, *tx_buf; - int dir, reg, cmd; - int retval; - - dbgvm("vmk80xx: %s\n", __func__); - - dir = 0; - - if (data[0]) - dir |= DIR_OUT; - - if (dev->board.model == VMK8061_MODEL) - dir |= DIR_IN; - - retval = rudimentary_check(dev, dir); - if (retval) - return retval; - - down(&dev->limit_sem); - - rx_buf = dev->usb_rx_buf; - tx_buf = dev->usb_tx_buf; - - if (data[0]) { - if (dev->board.model == VMK8055_MODEL) { - reg = VMK8055_DO_REG; - cmd = VMK8055_CMD_WRT_AD; - } else { /* VMK8061_MODEL */ - reg = VMK8061_DO_REG; - cmd = VMK8061_CMD_DO; - } - - tx_buf[reg] &= ~data[0]; - tx_buf[reg] |= (data[0] & data[1]); - - retval = vmk80xx_write_packet(dev, cmd); + down(&devpriv->limit_sem); - if (retval) + if (comedi_dio_update_state(s, data)) { + tx_buf[reg] = s->state; + ret = vmk80xx_write_packet(dev, cmd); + if (ret) goto out; } - if (dev->board.model == VMK8061_MODEL) { - reg = VMK8061_DO_REG; + if (devpriv->model == VMK8061_MODEL) { tx_buf[0] = VMK8061_CMD_RD_DO; - - retval = vmk80xx_read_packet(dev); - - if (!retval) { - data[1] = rx_buf[reg]; - retval = 2; - } + ret = vmk80xx_read_packet(dev); + if (ret) + goto out; + data[1] = rx_buf[reg]; } else { - data[1] = tx_buf[reg]; - retval = 2; + data[1] = s->state; } out: - up(&dev->limit_sem); + up(&devpriv->limit_sem); - return retval; + return ret ? ret : insn->n; } -static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_cnt_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; int chan; int reg[2]; int n; - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); - switch (dev->board.model) { + switch (devpriv->model) { case VMK8055_MODEL: if (!chan) reg[0] = VMK8055_CNT1_REG; @@ -979,9 +521,10 @@ static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, reg[0] = VMK8055_CNT2_REG; break; case VMK8061_MODEL: + default: reg[0] = VMK8061_CNT_REG; reg[1] = VMK8061_CNT_REG; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT; + devpriv->usb_tx_buf[0] = VMK8061_CMD_RD_CNT; break; } @@ -989,44 +532,39 @@ static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, if (vmk80xx_read_packet(dev)) break; - if (dev->board.model == VMK8055_MODEL) - data[n] = dev->usb_rx_buf[reg[0]]; + if (devpriv->model == VMK8055_MODEL) + data[n] = devpriv->usb_rx_buf[reg[0]]; else /* VMK8061_MODEL */ - data[n] = dev->usb_rx_buf[reg[0] * (chan + 1) + 1] - + 256 * dev->usb_rx_buf[reg[1] * 2 + 2]; + data[n] = devpriv->usb_rx_buf[reg[0] * (chan + 1) + 1] + + 256 * devpriv->usb_rx_buf[reg[1] * 2 + 2]; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_cnt_cinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_cnt_insn_config(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned int insn_cmd; int chan; int cmd; int reg; int n; - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); - insn_cmd = data[0]; if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET) return -EINVAL; + down(&devpriv->limit_sem); + chan = CR_CHAN(insn->chanspec); - if (dev->board.model == VMK8055_MODEL) { + if (devpriv->model == VMK8055_MODEL) { if (!chan) { cmd = VMK8055_CMD_RST_CNT1; reg = VMK8055_CNT1_REG; @@ -1035,7 +573,7 @@ static int vmk80xx_cnt_cinsn(struct comedi_device *cdev, reg = VMK8055_CNT2_REG; } - dev->usb_tx_buf[reg] = 0x00; + devpriv->usb_tx_buf[reg] = 0x00; } else { cmd = VMK8061_CMD_RST_CNT; } @@ -1044,29 +582,24 @@ static int vmk80xx_cnt_cinsn(struct comedi_device *cdev, if (vmk80xx_write_packet(dev, cmd)) break; - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_cnt_winsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_cnt_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned long debtime; unsigned long val; int chan; int cmd; int n; - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); chan = CR_CHAN(insn->chanspec); if (!chan) @@ -1087,69 +620,64 @@ static int vmk80xx_cnt_winsn(struct comedi_device *cdev, if (((val + 1) * val) < debtime * 1000 / 115) val += 1; - dev->usb_tx_buf[6 + chan] = val; + devpriv->usb_tx_buf[6 + chan] = val; if (vmk80xx_write_packet(dev, cmd)) break; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_pwm_rinsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_pwm_insn_read(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; + unsigned char *tx_buf; + unsigned char *rx_buf; int reg[2]; int n; - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_IN); - if (n) - return n; + down(&devpriv->limit_sem); - down(&dev->limit_sem); + tx_buf = devpriv->usb_tx_buf; + rx_buf = devpriv->usb_rx_buf; reg[0] = VMK8061_PWM_REG1; reg[1] = VMK8061_PWM_REG2; - dev->usb_tx_buf[0] = VMK8061_CMD_RD_PWM; + tx_buf[0] = VMK8061_CMD_RD_PWM; for (n = 0; n < insn->n; n++) { if (vmk80xx_read_packet(dev)) break; - data[n] = dev->usb_rx_buf[reg[0]] + 4 * dev->usb_rx_buf[reg[1]]; + data[n] = rx_buf[reg[0]] + 4 * rx_buf[reg[1]]; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_pwm_winsn(struct comedi_device *cdev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int vmk80xx_pwm_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - struct vmk80xx_usb *dev = cdev->private; + struct vmk80xx_private *devpriv = dev->private; unsigned char *tx_buf; int reg[2]; int cmd; int n; - dbgvm("vmk80xx: %s\n", __func__); - - n = rudimentary_check(dev, DIR_OUT); - if (n) - return n; - - down(&dev->limit_sem); + down(&devpriv->limit_sem); - tx_buf = dev->usb_tx_buf; + tx_buf = devpriv->usb_tx_buf; reg[0] = VMK8061_PWM_REG1; reg[1] = VMK8061_PWM_REG2; @@ -1177,385 +705,259 @@ static int vmk80xx_pwm_winsn(struct comedi_device *cdev, break; } - up(&dev->limit_sem); + up(&devpriv->limit_sem); return n; } -static int vmk80xx_attach(struct comedi_device *cdev, - struct comedi_devconfig *it) +static int vmk80xx_find_usb_endpoints(struct comedi_device *dev) { + struct vmk80xx_private *devpriv = dev->private; + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct usb_host_interface *iface_desc = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_desc; int i; - struct vmk80xx_usb *dev; - int n_subd; - struct comedi_subdevice *s; - int minor; - dbgvm("vmk80xx: %s\n", __func__); + if (iface_desc->desc.bNumEndpoints != 2) + return -ENODEV; - mutex_lock(&glb_mutex); + for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { + ep_desc = &iface_desc->endpoint[i].desc; - for (i = 0; i < VMK80XX_MAX_BOARDS; i++) - if (vmb[i].probed && !vmb[i].attached) - break; + if (usb_endpoint_is_int_in(ep_desc) || + usb_endpoint_is_bulk_in(ep_desc)) { + if (!devpriv->ep_rx) + devpriv->ep_rx = ep_desc; + continue; + } + + if (usb_endpoint_is_int_out(ep_desc) || + usb_endpoint_is_bulk_out(ep_desc)) { + if (!devpriv->ep_tx) + devpriv->ep_tx = ep_desc; + continue; + } + } - if (i == VMK80XX_MAX_BOARDS) { - mutex_unlock(&glb_mutex); + if (!devpriv->ep_rx || !devpriv->ep_tx) return -ENODEV; + + return 0; +} + +static int vmk80xx_alloc_usb_buffers(struct comedi_device *dev) +{ + struct vmk80xx_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; } - dev = &vmb[i]; + return 0; +} - down(&dev->limit_sem); +static int vmk80xx_init_subdevices(struct comedi_device *dev) +{ + const struct vmk80xx_board *boardinfo = comedi_board(dev); + struct vmk80xx_private *devpriv = dev->private; + struct comedi_subdevice *s; + int n_subd; + int ret; - cdev->board_name = dev->board.name; - cdev->private = dev; + down(&devpriv->limit_sem); - if (dev->board.model == VMK8055_MODEL) + if (devpriv->model == VMK8055_MODEL) n_subd = 5; else n_subd = 6; - - if (alloc_subdevices(cdev, n_subd) < 0) { - up(&dev->limit_sem); - mutex_unlock(&glb_mutex); - return -ENOMEM; + ret = comedi_alloc_subdevices(dev, n_subd); + if (ret) { + up(&devpriv->limit_sem); + return ret; } /* Analog input subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_AI; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = dev->board.ai_chans; - s->maxdata = (1 << dev->board.ai_bits) - 1; - s->range_table = dev->board.range; - s->insn_read = vmk80xx_ai_rinsn; + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = boardinfo->ai_nchans; + s->maxdata = boardinfo->ai_maxdata; + s->range_table = boardinfo->range; + s->insn_read = vmk80xx_ai_insn_read; /* Analog output subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_AO; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; - s->n_chan = dev->board.ao_chans; - s->maxdata = (1 << dev->board.ao_bits) - 1; - s->range_table = dev->board.range; - s->insn_write = vmk80xx_ao_winsn; - - if (dev->board.model == VMK8061_MODEL) { - s->subdev_flags |= SDF_READABLE; - s->insn_read = vmk80xx_ao_rinsn; + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; + s->n_chan = boardinfo->ao_nchans; + s->maxdata = 0x00ff; + s->range_table = boardinfo->range; + s->insn_write = vmk80xx_ao_insn_write; + if (devpriv->model == VMK8061_MODEL) { + s->subdev_flags |= SDF_READABLE; + s->insn_read = vmk80xx_ao_insn_read; } /* Digital input subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_DI; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = dev->board.di_chans; - s->maxdata = 1; - s->insn_read = vmk80xx_di_rinsn; - s->insn_bits = vmk80xx_di_bits; + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = boardinfo->di_nchans; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = vmk80xx_di_insn_bits; /* Digital output subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_DO; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; - s->n_chan = dev->board.do_chans; - s->maxdata = 1; - s->insn_write = vmk80xx_do_winsn; - s->insn_bits = vmk80xx_do_bits; - - if (dev->board.model == VMK8061_MODEL) { - s->subdev_flags |= SDF_READABLE; - s->insn_read = vmk80xx_do_rinsn; - } + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITEABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = vmk80xx_do_insn_bits; /* Counter subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_CNT; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_READABLE; - s->n_chan = dev->board.cnt_chans; - s->insn_read = vmk80xx_cnt_rinsn; - s->insn_config = vmk80xx_cnt_cinsn; - - if (dev->board.model == VMK8055_MODEL) { - s->subdev_flags |= SDF_WRITEABLE; - s->maxdata = (1 << dev->board.cnt_bits) - 1; - s->insn_write = vmk80xx_cnt_winsn; + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE; + s->n_chan = 2; + s->maxdata = boardinfo->cnt_maxdata; + s->insn_read = vmk80xx_cnt_insn_read; + s->insn_config = vmk80xx_cnt_insn_config; + if (devpriv->model == VMK8055_MODEL) { + s->subdev_flags |= SDF_WRITEABLE; + s->insn_write = vmk80xx_cnt_insn_write; } /* PWM subdevice */ - if (dev->board.model == VMK8061_MODEL) { - s = cdev->subdevices + VMK80XX_SUBD_PWM; - s->type = COMEDI_SUBD_PWM; - s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; - s->n_chan = dev->board.pwm_chans; - s->maxdata = (1 << dev->board.pwm_bits) - 1; - s->insn_read = vmk80xx_pwm_rinsn; - s->insn_write = vmk80xx_pwm_winsn; + if (devpriv->model == VMK8061_MODEL) { + s = &dev->subdevices[5]; + s->type = COMEDI_SUBD_PWM; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->n_chan = boardinfo->pwm_nchans; + s->maxdata = boardinfo->pwm_maxdata; + s->insn_read = vmk80xx_pwm_insn_read; + s->insn_write = vmk80xx_pwm_insn_write; } - dev->attached = 1; - - minor = cdev->minor; - - printk(KERN_INFO - "comedi%d: vmk80xx: board #%d [%s] attached to comedi\n", - minor, dev->count, dev->board.name); - - up(&dev->limit_sem); - mutex_unlock(&glb_mutex); - - return 0; -} - -static int vmk80xx_detach(struct comedi_device *cdev) -{ - struct vmk80xx_usb *dev; - int minor; - - dbgvm("vmk80xx: %s\n", __func__); - - if (!cdev) - return -EFAULT; - - dev = cdev->private; - if (!dev) - return -EFAULT; - - down(&dev->limit_sem); - - cdev->private = NULL; - dev->attached = 0; - - minor = cdev->minor; - - printk(KERN_INFO - "comedi%d: vmk80xx: board #%d [%s] detached from comedi\n", - minor, dev->count, dev->board.name); - - up(&dev->limit_sem); + up(&devpriv->limit_sem); return 0; } -static int vmk80xx_probe(struct usb_interface *intf, - const struct usb_device_id *id) +static int vmk80xx_auto_attach(struct comedi_device *dev, + unsigned long context) { - int i; - struct vmk80xx_usb *dev; - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *ep_desc; - size_t size; - - dbgvm("vmk80xx: %s\n", __func__); - - mutex_lock(&glb_mutex); - - for (i = 0; i < VMK80XX_MAX_BOARDS; i++) - if (!vmb[i].probed) - break; - - if (i == VMK80XX_MAX_BOARDS) { - mutex_unlock(&glb_mutex); - return -EMFILE; - } - - dev = &vmb[i]; - - memset(dev, 0x00, sizeof(struct vmk80xx_usb)); - dev->count = i; - - iface_desc = intf->cur_altsetting; - if (iface_desc->desc.bNumEndpoints != 2) - goto error; - - for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { - ep_desc = &iface_desc->endpoint[i].desc; - - if (usb_endpoint_is_int_in(ep_desc)) { - dev->ep_rx = ep_desc; - continue; - } + struct usb_interface *intf = comedi_to_usb_interface(dev); + const struct vmk80xx_board *boardinfo; + struct vmk80xx_private *devpriv; + int ret; - if (usb_endpoint_is_int_out(ep_desc)) { - dev->ep_tx = ep_desc; - continue; - } + boardinfo = &vmk80xx_boardinfo[context]; + dev->board_ptr = boardinfo; + dev->board_name = boardinfo->name; - if (usb_endpoint_is_bulk_in(ep_desc)) { - dev->ep_rx = ep_desc; - continue; - } + devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); + if (!devpriv) + return -ENOMEM; - if (usb_endpoint_is_bulk_out(ep_desc)) { - dev->ep_tx = ep_desc; - continue; - } - } + devpriv->model = boardinfo->model; - if (!dev->ep_rx || !dev->ep_tx) - goto error; + ret = vmk80xx_find_usb_endpoints(dev); + if (ret) + return ret; - size = le16_to_cpu(dev->ep_rx->wMaxPacketSize); - dev->usb_rx_buf = kmalloc(size, GFP_KERNEL); - if (!dev->usb_rx_buf) { - mutex_unlock(&glb_mutex); - return -ENOMEM; - } + ret = vmk80xx_alloc_usb_buffers(dev); + if (ret) + return ret; - size = le16_to_cpu(dev->ep_tx->wMaxPacketSize); - dev->usb_tx_buf = kmalloc(size, GFP_KERNEL); - if (!dev->usb_tx_buf) { - kfree(dev->usb_rx_buf); - mutex_unlock(&glb_mutex); - return -ENOMEM; - } + sema_init(&devpriv->limit_sem, 8); - dev->udev = interface_to_usbdev(intf); - dev->intf = intf; - - sema_init(&dev->limit_sem, 8); - init_waitqueue_head(&dev->read_wait); - init_waitqueue_head(&dev->write_wait); - - init_usb_anchor(&dev->rx_anchor); - init_usb_anchor(&dev->tx_anchor); - - usb_set_intfdata(intf, dev); - - switch (id->driver_info) { - case DEVICE_VMK8055: - dev->board.name = "K8055 (VM110)"; - dev->board.model = VMK8055_MODEL; - dev->board.range = &vmk8055_range; - dev->board.ai_chans = 2; - dev->board.ai_bits = 8; - dev->board.ao_chans = 2; - dev->board.ao_bits = 8; - dev->board.di_chans = 5; - dev->board.di_bits = 1; - dev->board.do_chans = 8; - dev->board.do_bits = 1; - dev->board.cnt_chans = 2; - dev->board.cnt_bits = 16; - dev->board.pwm_chans = 0; - dev->board.pwm_bits = 0; - break; - case DEVICE_VMK8061: - dev->board.name = "K8061 (VM140)"; - dev->board.model = VMK8061_MODEL; - dev->board.range = &vmk8061_range; - dev->board.ai_chans = 8; - dev->board.ai_bits = 10; - dev->board.ao_chans = 8; - dev->board.ao_bits = 8; - dev->board.di_chans = 8; - dev->board.di_bits = 1; - dev->board.do_chans = 8; - dev->board.do_bits = 1; - dev->board.cnt_chans = 2; - dev->board.cnt_bits = 0; - dev->board.pwm_chans = 1; - dev->board.pwm_bits = 10; - break; - } + usb_set_intfdata(intf, devpriv); - if (dev->board.model == VMK8061_MODEL) { + if (devpriv->model == VMK8061_MODEL) { vmk80xx_read_eeprom(dev, IC3_VERSION); - printk(KERN_INFO "comedi#: vmk80xx: %s\n", dev->fw.ic3_vers); + dev_info(&intf->dev, "%s\n", devpriv->fw.ic3_vers); if (vmk80xx_check_data_link(dev)) { vmk80xx_read_eeprom(dev, IC6_VERSION); - printk(KERN_INFO "comedi#: vmk80xx: %s\n", - dev->fw.ic6_vers); - } else { - dbgcm("comedi#: vmk80xx: no conn. to CPU\n"); + dev_info(&intf->dev, "%s\n", devpriv->fw.ic6_vers); } } - if (dev->board.model == VMK8055_MODEL) + if (devpriv->model == VMK8055_MODEL) vmk80xx_reset_device(dev); - dev->probed = 1; - - printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now attached\n", - dev->count, dev->board.name); - - mutex_unlock(&glb_mutex); - - comedi_usb_auto_config(dev->udev, BOARDNAME); - - return 0; -error: - mutex_unlock(&glb_mutex); - - return -ENODEV; + return vmk80xx_init_subdevices(dev); } -static void vmk80xx_disconnect(struct usb_interface *intf) +static void vmk80xx_detach(struct comedi_device *dev) { - struct vmk80xx_usb *dev = usb_get_intfdata(intf); - - dbgvm("vmk80xx: %s\n", __func__); + struct usb_interface *intf = comedi_to_usb_interface(dev); + struct vmk80xx_private *devpriv = dev->private; - if (!dev) + if (!devpriv) return; - comedi_usb_auto_unconfig(dev->udev); - - mutex_lock(&glb_mutex); - down(&dev->limit_sem); + down(&devpriv->limit_sem); - dev->probed = 0; - usb_set_intfdata(dev->intf, NULL); + usb_set_intfdata(intf, NULL); - usb_kill_anchored_urbs(&dev->rx_anchor); - usb_kill_anchored_urbs(&dev->tx_anchor); + kfree(devpriv->usb_rx_buf); + kfree(devpriv->usb_tx_buf); - kfree(dev->usb_rx_buf); - kfree(dev->usb_tx_buf); - - printk(KERN_INFO "comedi#: vmk80xx: board #%d [%s] now detached\n", - dev->count, dev->board.name); - - up(&dev->limit_sem); - mutex_unlock(&glb_mutex); + up(&devpriv->limit_sem); } -/* TODO: Add support for suspend, resume, pre_reset, - * post_reset and flush */ -static struct usb_driver vmk80xx_driver = { - .name = "vmk80xx", - .probe = vmk80xx_probe, - .disconnect = vmk80xx_disconnect, - .id_table = vmk80xx_id_table +static struct comedi_driver vmk80xx_driver = { + .module = THIS_MODULE, + .driver_name = "vmk80xx", + .auto_attach = vmk80xx_auto_attach, + .detach = vmk80xx_detach, }; -static struct comedi_driver driver_vmk80xx = { - .module = THIS_MODULE, - .driver_name = "vmk80xx", - .attach = vmk80xx_attach, - .detach = vmk80xx_detach -}; - -static int __init vmk80xx_init(void) +static int vmk80xx_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) { - int retval; - - printk(KERN_INFO "vmk80xx: version 0.8.01 " - "Manuel Gebele <forensixs@gmx.de>\n"); - - retval = comedi_driver_register(&driver_vmk80xx); - if (retval < 0) - return retval; - - return usb_register(&vmk80xx_driver); + return comedi_usb_auto_config(intf, &vmk80xx_driver, id->driver_info); } -static void __exit vmk80xx_exit(void) -{ - comedi_driver_unregister(&driver_vmk80xx); - usb_deregister(&vmk80xx_driver); -} +static const struct usb_device_id vmk80xx_usb_id_table[] = { + { USB_DEVICE(0x10cf, 0x5500), .driver_info = DEVICE_VMK8055 }, + { USB_DEVICE(0x10cf, 0x5501), .driver_info = DEVICE_VMK8055 }, + { USB_DEVICE(0x10cf, 0x5502), .driver_info = DEVICE_VMK8055 }, + { USB_DEVICE(0x10cf, 0x5503), .driver_info = DEVICE_VMK8055 }, + { USB_DEVICE(0x10cf, 0x8061), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8062), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8063), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8064), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8065), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8066), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8067), .driver_info = DEVICE_VMK8061 }, + { USB_DEVICE(0x10cf, 0x8068), .driver_info = DEVICE_VMK8061 }, + { } +}; +MODULE_DEVICE_TABLE(usb, vmk80xx_usb_id_table); + +static struct usb_driver vmk80xx_usb_driver = { + .name = "vmk80xx", + .id_table = vmk80xx_usb_id_table, + .probe = vmk80xx_usb_probe, + .disconnect = comedi_usb_auto_unconfig, +}; +module_comedi_usb_driver(vmk80xx_driver, vmk80xx_usb_driver); -module_init(vmk80xx_init); -module_exit(vmk80xx_exit); +MODULE_AUTHOR("Manuel Gebele <forensixs@gmx.de>"); +MODULE_DESCRIPTION("Velleman USB Board Low-Level Driver"); +MODULE_SUPPORTED_DEVICE("K8055/K8061 aka VM110/VM140"); +MODULE_VERSION("0.8.01"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/internal.h b/drivers/staging/comedi/internal.h deleted file mode 100644 index 434ce343336..00000000000 --- a/drivers/staging/comedi/internal.h +++ /dev/null @@ -1,12 +0,0 @@ -/* - * various internal comedi functions - */ -int do_rangeinfo_ioctl(struct comedi_device *dev, - struct comedi_rangeinfo __user *arg); -int insn_inval(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -int comedi_alloc_board_minor(struct device *hardware_device); -void comedi_free_board_minor(unsigned minor); -void comedi_reset_async_buf(struct comedi_async *async); -int comedi_buf_alloc(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned long new_size); diff --git a/drivers/staging/comedi/kcomedilib/Makefile b/drivers/staging/comedi/kcomedilib/Makefile index 18ee99bdde0..3aff8ed08e2 100644 --- a/drivers/staging/comedi/kcomedilib/Makefile +++ b/drivers/staging/comedi/kcomedilib/Makefile @@ -1,3 +1,5 @@ +ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG + obj-$(CONFIG_COMEDI_KCOMEDILIB) += kcomedilib.o kcomedilib-objs := kcomedilib_main.o diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index 0252b440885..8777f958c04 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -14,22 +14,14 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#define __NO_VERSION__ #include <linux/module.h> #include <linux/errno.h> #include <linux/kernel.h> #include <linux/sched.h> #include <linux/fcntl.h> -#include <linux/delay.h> -#include <linux/ioport.h> #include <linux/mm.h> #include <linux/io.h> @@ -43,57 +35,67 @@ MODULE_LICENSE("GPL"); struct comedi_device *comedi_open(const char *filename) { - struct comedi_device_file_info *dev_file_info; - struct comedi_device *dev; + struct comedi_device *dev, *retval = NULL; unsigned int minor; if (strncmp(filename, "/dev/comedi", 11) != 0) return NULL; - minor = simple_strtoul(filename + 11, NULL, 0); + if (kstrtouint(filename + 11, 0, &minor)) + return NULL; if (minor >= COMEDI_NUM_BOARD_MINORS) return NULL; - dev_file_info = comedi_get_device_file_info(minor); - if (dev_file_info == NULL) + dev = comedi_dev_get_from_minor(minor); + if (!dev) return NULL; - dev = dev_file_info->device; - if (dev == NULL || !dev->attached) - return NULL; + down_read(&dev->attach_lock); + if (dev->attached) + retval = dev; + else + retval = NULL; + up_read(&dev->attach_lock); - if (!try_module_get(dev->driver->module)) - return NULL; + if (retval == NULL) + comedi_dev_put(dev); - return dev; + return retval; } -EXPORT_SYMBOL(comedi_open); +EXPORT_SYMBOL_GPL(comedi_open); -int comedi_close(struct comedi_device *d) +int comedi_close(struct comedi_device *dev) { - struct comedi_device *dev = (struct comedi_device *)d; - - module_put(dev->driver->module); - + comedi_dev_put(dev); return 0; } -EXPORT_SYMBOL(comedi_close); +EXPORT_SYMBOL_GPL(comedi_close); -static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) +static int comedi_do_insn(struct comedi_device *dev, + struct comedi_insn *insn, + unsigned int *data) { struct comedi_subdevice *s; - int ret = 0; + int ret; + + mutex_lock(&dev->mutex); + + if (!dev->attached) { + ret = -EINVAL; + goto error; + } /* a subdevice instruction */ if (insn->subdev >= dev->n_subdevices) { ret = -EINVAL; goto error; } - s = dev->subdevices + insn->subdev; + s = &dev->subdevices[insn->subdev]; if (s->type == COMEDI_SUBD_UNUSED) { - printk(KERN_ERR "%d not useable subdevice\n", insn->subdev); + dev_err(dev->class_dev, + "%d not useable subdevice\n", insn->subdev); ret = -EIO; goto error; } @@ -102,7 +104,7 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) ret = comedi_check_chanlist(s, 1, &insn->chanspec); if (ret < 0) { - printk(KERN_ERR "bad chanspec\n"); + dev_err(dev->class_dev, "bad chanspec\n"); ret = -EINVAL; goto error; } @@ -115,11 +117,11 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) switch (insn->insn) { case INSN_BITS: - ret = s->insn_bits(dev, s, insn, insn->data); + ret = s->insn_bits(dev, s, insn, data); break; case INSN_CONFIG: /* XXX should check instruction length */ - ret = s->insn_config(dev, s, insn, insn->data); + ret = s->insn_config(dev, s, insn, data); break; default: ret = -EINVAL; @@ -129,8 +131,30 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) s->busy = NULL; error: + mutex_unlock(&dev->mutex); + return ret; +} + +int comedi_dio_get_config(struct comedi_device *dev, unsigned int subdev, + unsigned int chan, unsigned int *io) +{ + struct comedi_insn insn; + unsigned int data[2]; + int ret; + + memset(&insn, 0, sizeof(insn)); + insn.insn = INSN_CONFIG; + insn.n = 2; + insn.subdev = subdev; + insn.chanspec = CR_PACK(chan, 0, 0); + data[0] = INSN_CONFIG_DIO_QUERY; + data[1] = 0; + ret = comedi_do_insn(dev, &insn, data); + if (ret >= 0) + *io = data[1]; return ret; } +EXPORT_SYMBOL_GPL(comedi_dio_get_config); int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, unsigned int chan, unsigned int io) @@ -140,56 +164,89 @@ int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, memset(&insn, 0, sizeof(insn)); insn.insn = INSN_CONFIG; insn.n = 1; - insn.data = &io; insn.subdev = subdev; insn.chanspec = CR_PACK(chan, 0, 0); - return comedi_do_insn(dev, &insn); + return comedi_do_insn(dev, &insn, &io); } -EXPORT_SYMBOL(comedi_dio_config); +EXPORT_SYMBOL_GPL(comedi_dio_config); -int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev, - unsigned int mask, unsigned int *bits) +int comedi_dio_bitfield2(struct comedi_device *dev, unsigned int subdev, + unsigned int mask, unsigned int *bits, + unsigned int base_channel) { struct comedi_insn insn; unsigned int data[2]; + unsigned int n_chan; + unsigned int shift; int ret; + base_channel = CR_CHAN(base_channel); + n_chan = comedi_get_n_channels(dev, subdev); + if (base_channel >= n_chan) + return -EINVAL; + memset(&insn, 0, sizeof(insn)); insn.insn = INSN_BITS; + insn.chanspec = base_channel; insn.n = 2; - insn.data = data; insn.subdev = subdev; data[0] = mask; data[1] = *bits; - ret = comedi_do_insn(dev, &insn); - - *bits = data[1]; + /* + * Most drivers ignore the base channel in insn->chanspec. + * Fix this here if the subdevice has <= 32 channels. + */ + if (n_chan <= 32) { + shift = base_channel; + if (shift) { + insn.chanspec = 0; + data[0] <<= shift; + data[1] <<= shift; + } + } else { + shift = 0; + } + ret = comedi_do_insn(dev, &insn, data); + *bits = data[1] >> shift; return ret; } -EXPORT_SYMBOL(comedi_dio_bitfield); +EXPORT_SYMBOL_GPL(comedi_dio_bitfield2); int comedi_find_subdevice_by_type(struct comedi_device *dev, int type, unsigned int subd) { - if (subd > dev->n_subdevices) - return -ENODEV; - - for (; subd < dev->n_subdevices; subd++) { - if (dev->subdevices[subd].type == type) - return subd; - } - return -1; + struct comedi_subdevice *s; + int ret = -ENODEV; + + down_read(&dev->attach_lock); + if (dev->attached) + for (; subd < dev->n_subdevices; subd++) { + s = &dev->subdevices[subd]; + if (s->type == type) { + ret = subd; + break; + } + } + up_read(&dev->attach_lock); + return ret; } -EXPORT_SYMBOL(comedi_find_subdevice_by_type); +EXPORT_SYMBOL_GPL(comedi_find_subdevice_by_type); int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice) { - struct comedi_subdevice *s = dev->subdevices + subdevice; + int n; + + down_read(&dev->attach_lock); + if (!dev->attached || subdevice >= dev->n_subdevices) + n = 0; + else + n = dev->subdevices[subdevice].n_chan; + up_read(&dev->attach_lock); - return s->n_chan; + return n; } -EXPORT_SYMBOL(comedi_get_n_channels); +EXPORT_SYMBOL_GPL(comedi_get_n_channels); diff --git a/drivers/staging/comedi/proc.c b/drivers/staging/comedi/proc.c index 2aa487b6018..91dea25b572 100644 --- a/drivers/staging/comedi/proc.c +++ b/drivers/staging/comedi/proc.c @@ -1,99 +1,97 @@ /* - module/proc.c - /proc interface for comedi - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * /proc interface for comedi + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 1998 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ /* - This is some serious bloatware. - - Taken from Dave A.'s PCL-711 driver, 'cuz I thought it - was cool. -*/ + * This is some serious bloatware. + * + * Taken from Dave A.'s PCL-711 driver, 'cuz I thought it + * was cool. + */ -#define __NO_VERSION__ #include "comedidev.h" -#include "comedi_fops.h" +#include "comedi_internal.h" #include <linux/proc_fs.h> -#include <linux/string.h> +#include <linux/seq_file.h> -#ifdef CONFIG_PROC_FS -static int comedi_read(char *buf, char **start, off_t offset, int len, - int *eof, void *data) +static int comedi_read(struct seq_file *m, void *v) { int i; int devices_q = 0; - int l = 0; struct comedi_driver *driv; - l += sprintf(buf + l, - "comedi version " COMEDI_RELEASE "\n" - "format string: %s\n", - "\"%2d: %-20s %-20s %4d\", i, " - "driver_name, board_name, n_subdevices"); + seq_printf(m, "comedi version " COMEDI_RELEASE "\nformat string: %s\n", + "\"%2d: %-20s %-20s %4d\", i, driver_name, board_name, n_subdevices"); for (i = 0; i < COMEDI_NUM_BOARD_MINORS; i++) { - struct comedi_device_file_info *dev_file_info = - comedi_get_device_file_info(i); - struct comedi_device *dev; + struct comedi_device *dev = comedi_dev_get_from_minor(i); - if (dev_file_info == NULL) + if (!dev) continue; - dev = dev_file_info->device; + down_read(&dev->attach_lock); if (dev->attached) { devices_q = 1; - l += sprintf(buf + l, "%2d: %-20s %-20s %4d\n", - i, - dev->driver->driver_name, - dev->board_name, dev->n_subdevices); + seq_printf(m, "%2d: %-20s %-20s %4d\n", + i, dev->driver->driver_name, + dev->board_name, dev->n_subdevices); } + up_read(&dev->attach_lock); + comedi_dev_put(dev); } if (!devices_q) - l += sprintf(buf + l, "no devices\n"); + seq_puts(m, "no devices\n"); + mutex_lock(&comedi_drivers_list_lock); for (driv = comedi_drivers; driv; driv = driv->next) { - l += sprintf(buf + l, "%s:\n", driv->driver_name); - for (i = 0; i < driv->num_names; i++) { - l += sprintf(buf + l, " %s\n", - *(char **)((char *)driv->board_name + - i * driv->offset)); - } + seq_printf(m, "%s:\n", driv->driver_name); + for (i = 0; i < driv->num_names; i++) + seq_printf(m, " %s\n", + *(char **)((char *)driv->board_name + + i * driv->offset)); + if (!driv->num_names) - l += sprintf(buf + l, " %s\n", driv->driver_name); + seq_printf(m, " %s\n", driv->driver_name); } + mutex_unlock(&comedi_drivers_list_lock); - return l; + return 0; } -void comedi_proc_init(void) +/* + * seq_file wrappers for procfile show routines. + */ +static int comedi_proc_open(struct inode *inode, struct file *file) { - struct proc_dir_entry *comedi_proc; + return single_open(file, comedi_read, NULL); +} - comedi_proc = create_proc_entry("comedi", S_IFREG | S_IRUGO, NULL); - if (comedi_proc) - comedi_proc->read_proc = comedi_read; +static const struct file_operations comedi_proc_fops = { + .open = comedi_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +void comedi_proc_init(void) +{ + proc_create("comedi", 0644, NULL, &comedi_proc_fops); } void comedi_proc_cleanup(void) { remove_proc_entry("comedi", NULL); } -#endif diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index 148ec6fd6fd..b6849545b81 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -14,29 +14,32 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ #include <linux/uaccess.h> #include "comedidev.h" -#include "internal.h" +#include "comedi_internal.h" const struct comedi_lrange range_bipolar10 = { 1, {BIP_RANGE(10)} }; -EXPORT_SYMBOL(range_bipolar10); +EXPORT_SYMBOL_GPL(range_bipolar10); const struct comedi_lrange range_bipolar5 = { 1, {BIP_RANGE(5)} }; -EXPORT_SYMBOL(range_bipolar5); +EXPORT_SYMBOL_GPL(range_bipolar5); const struct comedi_lrange range_bipolar2_5 = { 1, {BIP_RANGE(2.5)} }; -EXPORT_SYMBOL(range_bipolar2_5); +EXPORT_SYMBOL_GPL(range_bipolar2_5); const struct comedi_lrange range_unipolar10 = { 1, {UNI_RANGE(10)} }; -EXPORT_SYMBOL(range_unipolar10); +EXPORT_SYMBOL_GPL(range_unipolar10); const struct comedi_lrange range_unipolar5 = { 1, {UNI_RANGE(5)} }; -EXPORT_SYMBOL(range_unipolar5); +EXPORT_SYMBOL_GPL(range_unipolar5); +const struct comedi_lrange range_unipolar2_5 = { 1, {UNI_RANGE(2.5)} }; +EXPORT_SYMBOL_GPL(range_unipolar2_5); +const struct comedi_lrange range_0_20mA = { 1, {RANGE_mA(0, 20)} }; +EXPORT_SYMBOL_GPL(range_0_20mA); +const struct comedi_lrange range_4_20mA = { 1, {RANGE_mA(4, 20)} }; +EXPORT_SYMBOL_GPL(range_4_20mA); +const struct comedi_lrange range_0_32mA = { 1, {RANGE_mA(0, 32)} }; +EXPORT_SYMBOL_GPL(range_0_32mA); const struct comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none} } }; -EXPORT_SYMBOL(range_unknown); +EXPORT_SYMBOL_GPL(range_unknown); /* COMEDI_RANGEINFO @@ -68,7 +71,7 @@ int do_rangeinfo_ioctl(struct comedi_device *dev, return -EINVAL; if (subd >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + subd; + s = &dev->subdevices[subd]; if (s->range_table) { lr = s->range_table; } else if (s->range_table_list) { @@ -80,8 +83,10 @@ int do_rangeinfo_ioctl(struct comedi_device *dev, } if (RANGE_LENGTH(it.range_type) != lr->length) { - DPRINTK("wrong length %d should be %d (0x%08x)\n", - RANGE_LENGTH(it.range_type), lr->length, it.range_type); + dev_dbg(dev->class_dev, + "wrong length %d should be %d (0x%08x)\n", + RANGE_LENGTH(it.range_type), + lr->length, it.range_type); return -EINVAL; } @@ -120,47 +125,42 @@ static int aref_invalid(struct comedi_subdevice *s, unsigned int chanspec) default: break; } - DPRINTK("subdevice does not support aref %i", aref); + dev_dbg(s->device->class_dev, "subdevice does not support aref %i", + aref); return 1; } -/* - This function checks each element in a channel/gain list to make - make sure it is valid. +/** + * comedi_check_chanlist() - Validate each element in a chanlist. + * @s: comedi_subdevice struct + * @n: number of elements in the chanlist + * @chanlist: the chanlist to validate */ int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist) { - int i; - int chan; - - if (s->range_table) { - for (i = 0; i < n; i++) - if (CR_CHAN(chanlist[i]) >= s->n_chan || - CR_RANGE(chanlist[i]) >= s->range_table->length - || aref_invalid(s, chanlist[i])) { - printk(KERN_ERR "bad chanlist[%d]=0x%08x " - "in_chan=%d range length=%d\n", i, - chanlist[i], s->n_chan, - s->range_table->length); - return -EINVAL; - } - } else if (s->range_table_list) { - for (i = 0; i < n; i++) { - chan = CR_CHAN(chanlist[i]); - if (chan >= s->n_chan || - CR_RANGE(chanlist[i]) >= - s->range_table_list[chan]->length - || aref_invalid(s, chanlist[i])) { - printk(KERN_ERR "bad chanlist[%d]=0x%08x\n", - i, chanlist[i]); - return -EINVAL; - } + struct comedi_device *dev = s->device; + unsigned int chanspec; + int chan, range_len, i; + + for (i = 0; i < n; i++) { + chanspec = chanlist[i]; + chan = CR_CHAN(chanspec); + if (s->range_table) + range_len = s->range_table->length; + else if (s->range_table_list && chan < s->n_chan) + range_len = s->range_table_list[chan]->length; + else + range_len = 0; + if (chan >= s->n_chan || + CR_RANGE(chanspec) >= range_len || + aref_invalid(s, chanspec)) { + dev_warn(dev->class_dev, + "bad chanlist[%d]=0x%08x chan=%d range length=%d\n", + i, chanspec, chan, range_len); + return -EINVAL; } - } else { - printk(KERN_ERR "comedi: (bug) no range type list!\n"); - return -EINVAL; } return 0; } -EXPORT_SYMBOL(comedi_check_chanlist); +EXPORT_SYMBOL_GPL(comedi_check_chanlist); |
